---
title: "Deploy Apify Scraper Runner"
description: "Run 190+ Cliqto Media Apify scrapers and export results to CSV or JSON."
category: "Automation"
url: https://railway.com/deploy/apify-scraper-runner
---

# Deploy Apify Scraper Runner

Run 190+ Cliqto Media Apify scrapers and export results to CSV or JSON.

**[Deploy Apify Scraper Runner on Railway](https://railway.com/template/apify-scraper-runner)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/apify-scraper-runner/manifest.json

- **Creator:** Cliqto Media
- **Category:** Automation

## Template content

### apify-scraper-runner https://cliqtomedia.com/assets/img/logo.svg

- **Image:** ghcr.io/railwayapp/function-bun:1.4.4
- **Start command:** `./run.sh Ly8gQ2xpcXRvIE1lZGlhIEFwaWZ5IFNjcmFwZXIgUnVubmVyIGZvciBSYWlsd2F5OiBvbmUtZmlsZSBCdW4gc2VydmVyIChSYWlsd2F5IEZ1bmN0aW9uKS4KLy8gUHVibGljIGNhbGxzIChjYXRhbG9nLCBpbnB1dCBzY2hlbWEpIG5lZWQgbm8gdG9rZW4uIFJ1bnMgYW5kIHJlc3VsdHMgdXNlIHlvdXIgb3duCi8vIEFwaWZ5IHRva2VuIGZyb20gdGhlIEFQSUZZX1RPS0VOIHZhcmlhYmxlLCBzZW50IGluIGEgaGVhZGVyLCBuZXZlciBpbiBhIFVSTCBvciB0byB0aGUgYnJvd3Nlci4KCmV4cG9ydCBjb25zdCBBUEkgPSAiaHR0cHM6Ly9hcGkuYXBpZnkuY29tL3YyIjsKZXhwb3J0IGNvbnN0IE9XTkVSID0gImNsaXF0b21lZGlhIjsKZXhwb3J0IGNvbnN0IFNJVEUgPSAiaHR0cHM6Ly9jbGlxdG9tZWRpYS5jb20vYWN0b3JzLyI7CmV4cG9ydCBjb25zdCBVVE0gPSAidXRtX3NvdXJjZT1yYWlsd2F5JnV0bV9tZWRpdW09dGVtcGxhdGUmdXRtX2NhbXBhaWduPXByb21vLTIwMjYtMTEiOwpleHBvcnQgY29uc3QgVE9LRU5fVVJMID0gImh0dHBzOi8vY29uc29sZS5hcGlmeS5jb20vc2V0dGluZ3MvaW50ZWdyYXRpb25zIjsKZXhwb3J0IGNvbnN0IFNJR05VUF9VUkwgPSAiaHR0cHM6Ly9jb25zb2xlLmFwaWZ5LmNvbS9zaWduLXVwIjsKZXhwb3J0IGNvbnN0IERFRkFVTFRfTElNSVQgPSAyMDsKZXhwb3J0IGNvbnN0IE1BWF9JVEVNUyA9IDEwMDAwOwpleHBvcnQgY29uc3QgTUFYX1VTRCA9IDI1Owpjb25zdCBISURERU4gPSAvb25seWZhbnN8YWR1bHR8bnNmdy9pOwpjb25zdCBURVJNSU5BTCA9IG5ldyBTZXQoWyJTVUNDRUVERUQiLCAiRkFJTEVEIiwgIkFCT1JURUQiLCAiVElNRUQtT1VUIl0pOwoKZXhwb3J0IHR5cGUgSnNvbiA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+OwoKLy8gVGVzdGVkIGV4YW1wbGUgaW5wdXQgZm9yIDEwIHBvcHVsYXIgc2NyYXBlcnMgKGVhY2ggY2hlY2tlZCB3aXRoIGEgcmVhbCBydW4pLgpleHBvcnQgY29uc3QgRVhBTVBMRVM6IFJlY29yZDxzdHJpbmcsIEpzb24+ID0gewogICJ5b3V0dWJlLXRyYW5zY3JpcHQtc2NyYXBlciI6IHsgdmlkZW9VcmxzOiBbImpOUVhBQzlJVlJ3Il0sIHByZWZlcnJlZExhbmd1YWdlczogWyJlbiJdIH0sCiAgInJlZGRpdC1zY3JhcGVyIjogeyBtb2RlOiAic3VicmVkZGl0Iiwgc3VicmVkZGl0czogWyJkYXRhc2NpZW5jZSJdLCBtYXhQb3N0czogMTAsIG1heENvbW1lbnRzUGVyUG9zdDogMCB9LAogICJnb29nbGUtdHJlbmRzLXNjcmFwZXIiOiB7IHNlYXJjaFRlcm1zOiBbIndlYiBzY3JhcGluZyJdLCB0aW1lUmFuZ2U6ICJ0b2RheSAxMi1tIiB9LAogICJnb29nbGUtYXV0b2NvbXBsZXRlLXNjcmFwZXIiOiB7IGtleXdvcmRzOiBbInB5dGhvbiBwYW5kYXMiXSwgbGFuZ3VhZ2U6ICJlbiIsIGNvdW50cnk6ICJ1cyIsIG1heFJlc3VsdHM6IDUwIH0sCiAgImdvb2dsZS1wbGF5LXJldmlld3Mtc2NyYXBlciI6IHsgYXBwSWRzOiBbImNvbS5nb29nbGUuYW5kcm9pZC5hcHBzLnRyYW5zbGF0ZSJdLCBtYXhSZXZpZXdzUGVyQXBwOiAyMCwgbWF4VG90YWxSZXZpZXdzOiAyMCB9LAogICJ0cnVzdHBpbG90LXJldmlld3Mtc2NyYXBlciI6IHsgY29tcGFueURvbWFpbnM6IFsiYXBpZnkuY29tIl0sIG1heFJldmlld3M6IDIwIH0sCiAgInBpbnRlcmVzdC1zZWFyY2gtc2NyYXBlciI6IHsgbW9kZTogInNlYXJjaCIsIHF1ZXJpZXM6IFsiaG9tZSBvZmZpY2UgaWRlYXMiXSwgbWF4SXRlbXM6IDIwIH0sCiAgInRocmVhZHMtc2NyYXBlciI6IHsgbW9kZTogInByb2ZpbGUiLCB1c2VybmFtZXM6IFsienVjayJdLCBtYXhJdGVtczogMjAgfSwKICAid2Vic2l0ZS1jb250YWN0cy1zY3JhcGVyIjogeyBzdGFydFVybHM6IFt7IHVybDogImh0dHBzOi8vd3d3LnB5dGhvbi5vcmcvIiB9XSB9LAogICJnb29nbGUtcGF0ZW50cy1zY3JhcGVyIjogeyBwdWJsaWNhdGlvbk51bWJlcnM6IFsiVVM5MDE0OTA1QjEiXSB9LAp9OwoKZXhwb3J0IGludGVyZmFjZSBDYXRhbG9nQWN0b3IgewogIG5hbWU6IHN0cmluZzsKICB0aXRsZTogc3RyaW5nOwogIGRlc2NyaXB0aW9uOiBzdHJpbmc7CiAgY2F0ZWdvcmllczogc3RyaW5nW107CiAgcGljdHVyZTogc3RyaW5nOwogIHVzZXJzOiBudW1iZXI7CiAgcHJpY2U6IG51bWJlciB8IG51bGw7CiAgdW5pdDogc3RyaW5nOwp9CgpleHBvcnQgaW50ZXJmYWNlIFNjaGVtYVByb3AgewogIHRpdGxlPzogc3RyaW5nOwogIHR5cGU/OiBzdHJpbmc7CiAgZWRpdG9yPzogc3RyaW5nOwogIGRlc2NyaXB0aW9uPzogc3RyaW5nOwogIGVudW0/OiB1bmtub3duW107CiAgZW51bVRpdGxlcz86IHN0cmluZ1tdOwogIGRlZmF1bHQ/OiB1bmtub3duOwogIHByZWZpbGw/OiB1bmtub3duOwogIG1pbmltdW0/OiBudW1iZXI7CiAgbWF4aW11bT86IG51bWJlcjsKICBzZWN0aW9uQ2FwdGlvbj86IHN0cmluZzsKICBpc1NlY3JldD86IGJvb2xlYW47CiAgaXRlbXM/OiB7IHR5cGU/OiBzdHJpbmc7IGVudW0/OiB1bmtub3duW107IGVudW1UaXRsZXM/OiBzdHJpbmdbXTsgcHJvcGVydGllcz86IEpzb247IHJlcXVpcmVkPzogc3RyaW5nW10gfTsKfQoKZXhwb3J0IGludGVyZmFjZSBJbnB1dFNjaGVtYSB7CiAgcHJvcGVydGllczogUmVjb3JkPHN0cmluZywgU2NoZW1hUHJvcD47CiAgcmVxdWlyZWQ/OiBzdHJpbmdbXTsKfQoKZXhwb3J0IGludGVyZmFjZSBBY3RvckluZm8gewogIG5hbWU6IHN0cmluZzsKICBmdWxsTmFtZTogc3RyaW5nOwogIHRpdGxlOiBzdHJpbmc7CiAgZGVzY3JpcHRpb246IHN0cmluZzsKICBwaWN0dXJlOiBzdHJpbmc7CiAgcHJpY2U6IG51bWJlciB8IG51bGw7CiAgdW5pdDogc3RyaW5nOwogIHBhZ2VFeGFtcGxlOiBKc29uOwogIHNjaGVtYTogSW5wdXRTY2hlbWEgfCBudWxsOwp9CgpleHBvcnQgaW50ZXJmYWNlIFJ1biB7CiAgaWQ6IHN0cmluZzsKICBzdGF0dXM6IHN0cmluZzsKICBkYXRhc2V0SWQ6IHN0cmluZzsKICBpdGVtQ291bnQ6IG51bWJlcjsKICBzdGF0dXNNZXNzYWdlOiBzdHJpbmc7CiAgdXNkOiBudW1iZXIgfCBudWxsOwogIHVybDogc3RyaW5nOwogIHN0b3BwZWQ/OiBib29sZWFuOwp9CgpleHBvcnQgdHlwZSBGaWVsZEtpbmQgPSAiYm9vbGVhbiIgfCAibnVtYmVyIiB8ICJzZWxlY3QiIHwgIm11bHRpc2VsZWN0IiB8ICJ0ZXh0IiB8ICJ0ZXh0YXJlYSIgfCAibGlzdCIgfCAidXJscyIgfCAianNvbiI7CgpleHBvcnQgaW50ZXJmYWNlIEZpZWxkIHsKICBrZXk6IHN0cmluZzsKICBsYWJlbDogc3RyaW5nOwogIGtpbmQ6IEZpZWxkS2luZDsKICBoZWxwOiBzdHJpbmc7CiAgcmVxdWlyZWQ6IGJvb2xlYW47CiAgb3B0aW9uczogeyB2YWx1ZTogc3RyaW5nOyBsYWJlbDogc3RyaW5nIH1bXTsKICBtaW4/OiBudW1iZXI7CiAgbWF4PzogbnVtYmVyOwogIGlzTGltaXQ6IGJvb2xlYW47CiAgYWR2YW5jZWQ6IGJvb2xlYW47Cn0KCmV4cG9ydCBjbGFzcyBBcGlmeUVycm9yIGV4dGVuZHMgRXJyb3IgewogIHN0YXR1czogbnVtYmVyOwogIC8qKiBMaW5rIHRvIHRoZSBBcGlmeSBydW4gdGhpcyBlcnJvciBpcyBhYm91dCwgaWYgYW55LiAqLwogIHVybD86IHN0cmluZzsKICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcsIHN0YXR1cyA9IDAsIHVybD86IHN0cmluZykgewogICAgc3VwZXIobWVzc2FnZSk7CiAgICB0aGlzLnN0YXR1cyA9IHN0YXR1czsKICAgIGlmICh1cmwgIT09IHVuZGVmaW5lZCkgdGhpcy51cmwgPSB1cmw7CiAgfQp9Cgpjb25zdCBoYXMgPSAobzogb2JqZWN0LCBrOiBzdHJpbmcpID0+IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvLCBrKTsKY29uc3QgY2xvbmUgPSA8VCw+KHY6IFQpOiBUID0+IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkodikpOwoKZXhwb3J0IGZ1bmN0aW9uIHNpdGVVcmwobmFtZT86IHN0cmluZyk6IHN0cmluZyB7CiAgcmV0dXJuIG5hbWUgPyBgJHtTSVRFfSR7ZW5jb2RlVVJJQ29tcG9uZW50KG5hbWUpfS8/JHtVVE19YCA6IGAke1NJVEV9PyR7VVRNfWA7Cn0KCmV4cG9ydCBmdW5jdGlvbiBzdG9yZVVybChuYW1lOiBzdHJpbmcpOiBzdHJpbmcgewogIHJldHVybiBgaHR0cHM6Ly9hcGlmeS5jb20vJHtPV05FUn0vJHtlbmNvZGVVUklDb21wb25lbnQobmFtZSl9YDsKfQoKLy8gLS0tLS0tLS0tLSBBUEkgLS0tLS0tLS0tLQoKYXN5bmMgZnVuY3Rpb24gY2FsbChwYXRoOiBzdHJpbmcsIGluaXQ6IFJlcXVlc3RJbml0ID0ge30sIHRva2VuPzogc3RyaW5nKTogUHJvbWlzZTxhbnk+IHsKICBjb25zdCBoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307CiAgaWYgKGluaXQuYm9keSkgaGVhZGVyc1siQ29udGVudC1UeXBlIl0gPSAiYXBwbGljYXRpb24vanNvbiI7CiAgaWYgKHRva2VuKSBoZWFkZXJzWyJBdXRob3JpemF0aW9uIl0gPSBgQmVhcmVyICR7dG9rZW4udHJpbSgpfWA7CiAgbGV0IHJlczogUmVzcG9uc2U7CiAgdHJ5IHsKICAgIHJlcyA9IGF3YWl0IGZldGNoKGAke0FQSX0ke3BhdGh9YCwgeyAuLi5pbml0LCBoZWFkZXJzIH0pOwogIH0gY2F0Y2ggewogICAgdGhyb3cgbmV3IEFwaWZ5RXJyb3IoIkNhbm5vdCByZWFjaCB0aGUgQXBpZnkgQVBJLiBDaGVjayB5b3VyIGludGVybmV0IGNvbm5lY3Rpb24gYW5kIHRyeSBhZ2Fpbi4iKTsKICB9CiAgY29uc3QgdGV4dCA9IGF3YWl0IHJlcy50ZXh0KCk7CiAgbGV0IGpzb246IGFueSA9IG51bGw7CiAgdHJ5IHsganNvbiA9IHRleHQgPyBKU09OLnBhcnNlKHRleHQpIDogbnVsbDsgfSBjYXRjaCB7IGpzb24gPSBudWxsOyB9CiAgaWYgKCFyZXMub2spIHsKICAgIGxldCBtZXNzYWdlOiBzdHJpbmcgPSBqc29uPy5lcnJvcj8ubWVzc2FnZSB8fCBgQXBpZnkgQVBJIGVycm9yICR7cmVzLnN0YXR1c31gOwogICAgaWYgKHJlcy5zdGF0dXMgPT09IDQwMSkgbWVzc2FnZSA9ICJZb3VyIEFwaWZ5IHRva2VuIHdhcyByZWplY3RlZC4gQ29weSBpdCBhZ2FpbiBmcm9tIEFwaWZ5IENvbnNvbGUgXHUyMTkyIFNldHRpbmdzIFx1MjE5MiBBUEkgJiBJbnRlZ3JhdGlvbnMuIjsKICAgIGlmIChyZXMuc3RhdHVzID09PSA0MDIpIG1lc3NhZ2UgPSAiWW91ciBBcGlmeSBhY2NvdW50IGhhcyBubyBjcmVkaXQgbGVmdCBmb3IgdGhpcyBydW4uIENoZWNrIHlvdXIgcGxhbiBpbiBBcGlmeSBDb25zb2xlIFx1MjE5MiBCaWxsaW5nLiI7CiAgICB0aHJvdyBuZXcgQXBpZnlFcnJvcihtZXNzYWdlLCByZXMuc3RhdHVzKTsKICB9CiAgcmV0dXJuIGpzb247Cn0KCi8qKiAibmFtZSIsICJjbGlxdG9tZWRpYS9uYW1lIiwgImNsaXF0b21lZGlhfm5hbWUiIG9yIGFuIGFwaWZ5LmNvbSAvIGNsaXF0b21lZGlhLmNvbSBsaW5rIFx1MjE5MiB7b3duZXIsIG5hbWV9LiAqLwpleHBvcnQgZnVuY3Rpb24gcGFyc2VBY3RvclJlZihyYXc6IHN0cmluZyk6IHsgb3duZXI6IHN0cmluZzsgbmFtZTogc3RyaW5nIH0gfCBudWxsIHsKICBjb25zdCBzID0gU3RyaW5nKHJhdyB8fCAiIikudHJpbSgpOwogIGlmICghcykgcmV0dXJuIG51bGw7CiAgbGV0IG0gPSBzLm1hdGNoKC9jbGlxdG9tZWRpYVwuY29tXC9hY3RvcnNcLyhbXHcuLV0rKS9pKTsKICBpZiAobT8uWzFdKSByZXR1cm4geyBvd25lcjogT1dORVIsIG5hbWU6IG1bMV0udG9Mb3dlckNhc2UoKSB9OwogIG0gPSBzLm1hdGNoKC9hcGlmeVwuY29tXC8oPzphY3RvcnNcLyk/KFtcdy4tXSspWy9+XShbXHcuLV0rKS9pKTsKICBpZiAobT8uWzFdICYmIG1bMl0pIHJldHVybiB7IG93bmVyOiBtWzFdLnRvTG93ZXJDYXNlKCksIG5hbWU6IG1bMl0udG9Mb3dlckNhc2UoKSB9OwogIG0gPSBzLm1hdGNoKC9eKFtcdy4tXSspWy9+XShbXHcuLV0rKSQvKTsKICBpZiAobT8uWzFdICYmIG1bMl0pIHJldHVybiB7IG93bmVyOiBtWzFdLnRvTG93ZXJDYXNlKCksIG5hbWU6IG1bMl0udG9Mb3dlckNhc2UoKSB9OwogIGlmICgvXltcdy4tXSskLy50ZXN0KHMpKSByZXR1cm4geyBvd25lcjogT1dORVIsIG5hbWU6IHMudG9Mb3dlckNhc2UoKSB9OwogIHJldHVybiBudWxsOwp9CgpmdW5jdGlvbiBwcmltYXJ5UHJpY2UoaW5mbzogYW55KTogeyBwcmljZTogbnVtYmVyIHwgbnVsbDsgdW5pdDogc3RyaW5nIH0gewogIGNvbnN0IGV2ZW50cyA9IGluZm8/LnByaWNpbmdQZXJFdmVudD8uYWN0b3JDaGFyZ2VFdmVudHM7CiAgaWYgKCFldmVudHMpIHJldHVybiB7IHByaWNlOiBudWxsLCB1bml0OiAicmVzdWx0IiB9OwogIGNvbnN0IGxpc3Q6IGFueVtdID0gT2JqZWN0LnZhbHVlcyhldmVudHMpOwogIGNvbnN0IGV2ID0gbGlzdC5maW5kKGUgPT4gZS5pc1ByaW1hcnlFdmVudCkgfHwgbGlzdC5maW5kKGUgPT4gIS9zdGFydC9pLnRlc3QoZS5ldmVudFRpdGxlIHx8ICIiKSk7CiAgaWYgKCFldikgcmV0dXJuIHsgcHJpY2U6IG51bGwsIHVuaXQ6ICJyZXN1bHQiIH07CiAgY29uc3QgdGllciA9IGV2LmV2ZW50VGllcmVkUHJpY2luZ1VzZD8uRlJFRT8udGllcmVkRXZlbnRQcmljZVVzZDsKICBjb25zdCBwcmljZSA9IHRpZXIgIT0gbnVsbCA/IHRpZXIgOiBldi5ldmVudFByaWNlVXNkICE9IG51bGwgPyBldi5ldmVudFByaWNlVXNkIDogbnVsbDsKICByZXR1cm4geyBwcmljZSwgdW5pdDogU3RyaW5nKGV2LmV2ZW50VGl0bGUgfHwgInJlc3VsdCIpLnRvTG93ZXJDYXNlKCkgfTsKfQoKZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZldGNoQ2F0YWxvZygpOiBQcm9taXNlPENhdGFsb2dBY3RvcltdPiB7CiAgY29uc3Qgb3V0OiBDYXRhbG9nQWN0b3JbXSA9IFtdOwogIGZvciAobGV0IG9mZnNldCA9IDA7IG9mZnNldCA8IDMwMDA7IG9mZnNldCArPSAyMDApIHsKICAgIGNvbnN0IHBhZ2UgPSBhd2FpdCBjYWxsKGAvc3RvcmU/dXNlcm5hbWU9JHtPV05FUn0mbGltaXQ9MjAwJm9mZnNldD0ke29mZnNldH1gKTsKICAgIGZvciAoY29uc3QgYSBvZiBwYWdlLmRhdGEuaXRlbXMpIHsKICAgICAgY29uc3QgbmFtZSA9IFN0cmluZyhhLm5hbWUgfHwgIiIpOwogICAgICBpZiAoU3RyaW5nKGEudXNlcm5hbWUgfHwgIiIpLnRvTG93ZXJDYXNlKCkgIT09IE9XTkVSKSBjb250aW51ZTsKICAgICAgaWYgKEhJRERFTi50ZXN0KG5hbWUpIHx8IEhJRERFTi50ZXN0KFN0cmluZyhhLnRpdGxlIHx8ICIiKSkpIGNvbnRpbnVlOwogICAgICBjb25zdCBwciA9IHByaW1hcnlQcmljZShhLmN1cnJlbnRQcmljaW5nSW5mbyk7CiAgICAgIG91dC5wdXNoKHsKICAgICAgICBuYW1lLAogICAgICAgIHRpdGxlOiBTdHJpbmcoYS50aXRsZSB8fCBuYW1lKSwKICAgICAgICBkZXNjcmlwdGlvbjogU3RyaW5nKGEuZGVzY3JpcHRpb24gfHwgIiIpLAogICAgICAgIGNhdGVnb3JpZXM6IGEuY2F0ZWdvcmllcyB8fCBbXSwKICAgICAgICBwaWN0dXJlOiBTdHJpbmcoYS5waWN0dXJlVXJsIHx8ICIiKSwKICAgICAgICB1c2VyczogTnVtYmVyKGEuc3RhdHM/LnRvdGFsVXNlcnMgfHwgMCksCiAgICAgICAgcHJpY2U6IHByLnByaWNlLAogICAgICAgIHVuaXQ6IHByLnVuaXQsCiAgICAgIH0pOwogICAgfQogICAgaWYgKG9mZnNldCArIDIwMCA+PSBwYWdlLmRhdGEudG90YWwgfHwgIXBhZ2UuZGF0YS5pdGVtcy5sZW5ndGgpIGJyZWFrOwogIH0KICByZXR1cm4gb3V0LnNvcnQoKGEsIGIpID0+CiAgICBOdW1iZXIoaGFzKEVYQU1QTEVTLCBiLm5hbWUpKSAtIE51bWJlcihoYXMoRVhBTVBMRVMsIGEubmFtZSkpIHx8IGIudXNlcnMgLSBhLnVzZXJzIHx8IGEudGl0bGUubG9jYWxlQ29tcGFyZShiLnRpdGxlKSk7Cn0KCmV4cG9ydCBmdW5jdGlvbiBzZWFyY2hDYXRhbG9nKGxpc3Q6IENhdGFsb2dBY3RvcltdLCBxOiBzdHJpbmcpOiBDYXRhbG9nQWN0b3JbXSB7CiAgY29uc3Qgd29yZHMgPSBTdHJpbmcocSB8fCAiIikudG9Mb3dlckNhc2UoKS5zcGxpdCgvXHMrLykuZmlsdGVyKEJvb2xlYW4pOwogIGlmICghd29yZHMubGVuZ3RoKSByZXR1cm4gbGlzdDsKICByZXR1cm4gbGlzdC5maWx0ZXIoYSA9PiB7CiAgICBjb25zdCBoYXkgPSBgJHthLnRpdGxlfSAke2EubmFtZX0gJHthLmRlc2NyaXB0aW9ufSAke2EuY2F0ZWdvcmllcy5qb2luKCIgIil9YC50b0xvd2VyQ2FzZSgpOwogICAgcmV0dXJuIHdvcmRzLmV2ZXJ5KHcgPT4gaGF5LmluY2x1ZGVzKHcpKTsKICB9KTsKfQoKZnVuY3Rpb24gcGFyc2VKc29uT2JqZWN0KHM6IHVua25vd24pOiBKc29uIHsKICBpZiAodHlwZW9mIHMgIT09ICJzdHJpbmciKSByZXR1cm4ge307CiAgdHJ5IHsKICAgIGNvbnN0IHYgPSBKU09OLnBhcnNlKHMpOwogICAgcmV0dXJuIHYgJiYgdHlwZW9mIHYgPT09ICJvYmplY3QiICYmICFBcnJheS5pc0FycmF5KHYpID8gdiA6IHt9OwogIH0gY2F0Y2ggeyByZXR1cm4ge307IH0KfQoKLyoqIEFjdG9yIGluZm8gKyBpbnB1dCBzY2hlbWEuIFJlamVjdHMgQWN0b3JzIGJ5IG90aGVyIGF1dGhvcnMuICovCmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaEFjdG9yKHJhdzogc3RyaW5nKTogUHJvbWlzZTxBY3RvckluZm8+IHsKICBjb25zdCByZWYgPSBwYXJzZUFjdG9yUmVmKHJhdyk7CiAgaWYgKCFyZWYpIHRocm93IG5ldyBBcGlmeUVycm9yKCJUeXBlIGEgc2NyYXBlciBuYW1lLCBzdWNoIGFzIHJlZGRpdC1zY3JhcGVyLCBvciBwYXN0ZSBpdHMgbGluay4iKTsKICBpZiAocmVmLm93bmVyICE9PSBPV05FUikgewogICAgdGhyb3cgbmV3IEFwaWZ5RXJyb3IoYE9ubHkgQ2xpcXRvIE1lZGlhIHNjcmFwZXJzIHJ1biBoZXJlIChjbGlxdG9tZWRpYS9cdTIwMjYpLiBcdTIwMWMke3JlZi5vd25lcn0vJHtyZWYubmFtZX1cdTIwMWQgaXMgYnkgYW5vdGhlciBhdXRob3IuYCk7CiAgfQogIGxldCBhY3Q6IGFueTsKICB0cnkgewogICAgYWN0ID0gYXdhaXQgY2FsbChgL2FjdHMvJHtPV05FUn1+JHtlbmNvZGVVUklDb21wb25lbnQocmVmLm5hbWUpfWApOwogIH0gY2F0Y2ggKGUpIHsKICAgIGlmIChlIGluc3RhbmNlb2YgQXBpZnlFcnJvciAmJiBlLnN0YXR1cyA9PT0gNDA0KSB0aHJvdyBuZXcgQXBpZnlFcnJvcihgTm8gQ2xpcXRvIE1lZGlhIHNjcmFwZXIgaXMgY2FsbGVkIFx1MjAxYyR7cmVmLm5hbWV9XHUyMDFkLiBTZWFyY2ggdGhlIGxpc3QgaW5zdGVhZC5gLCA0MDQpOwogICAgdGhyb3cgZTsKICB9CiAgY29uc3QgZCA9IGFjdC5kYXRhOwogIGlmIChTdHJpbmcoZC51c2VybmFtZSB8fCAiIikudG9Mb3dlckNhc2UoKSAhPT0gT1dORVIpIHRocm93IG5ldyBBcGlmeUVycm9yKCJPbmx5IENsaXF0byBNZWRpYSBzY3JhcGVycyBydW4gaGVyZS4iKTsKICBsZXQgc2NoZW1hOiBJbnB1dFNjaGVtYSB8IG51bGwgPSBudWxsOwogIHRyeSB7CiAgICBjb25zdCBidWlsZCA9IGF3YWl0IGNhbGwoYC9hY3RzLyR7T1dORVJ9fiR7ZW5jb2RlVVJJQ29tcG9uZW50KHJlZi5uYW1lKX0vYnVpbGRzL2RlZmF1bHRgKTsKICAgIGNvbnN0IHBhcnNlZCA9IGJ1aWxkLmRhdGEuaW5wdXRTY2hlbWEgPyBKU09OLnBhcnNlKGJ1aWxkLmRhdGEuaW5wdXRTY2hlbWEpIDogbnVsbDsKICAgIGlmIChwYXJzZWQgJiYgdHlwZW9mIHBhcnNlZCA9PT0gIm9iamVjdCIgJiYgcGFyc2VkLnByb3BlcnRpZXMpIHNjaGVtYSA9IHBhcnNlZDsKICB9IGNhdGNoIHsgc2NoZW1hID0gbnVsbDsgfQogIGNvbnN0IGluZm9zID0gZC5wcmljaW5nSW5mb3MgfHwgW107CiAgY29uc3QgcHIgPSBwcmltYXJ5UHJpY2UoaW5mb3MubGVuZ3RoID8gaW5mb3NbaW5mb3MubGVuZ3RoIC0gMV0gOiBudWxsKTsKICByZXR1cm4gewogICAgbmFtZTogU3RyaW5nKGQubmFtZSksCiAgICBmdWxsTmFtZTogYCR7T1dORVJ9LyR7ZC5uYW1lfWAsCiAgICB0aXRsZTogU3RyaW5nKGQudGl0bGUgfHwgZC5uYW1lKSwKICAgIGRlc2NyaXB0aW9uOiBTdHJpbmcoZC5kZXNjcmlwdGlvbiB8fCAiIiksCiAgICBwaWN0dXJlOiBTdHJpbmcoZC5waWN0dXJlVXJsIHx8ICIiKSwKICAgIHByaWNlOiBwci5wcmljZSwKICAgIHVuaXQ6IHByLnVuaXQsCiAgICBwYWdlRXhhbXBsZTogcGFyc2VKc29uT2JqZWN0KGQuZXhhbXBsZVJ1bklucHV0Py5ib2R5KSwKICAgIHNjaGVtYSwKICB9Owp9CgpleHBvcnQgYXN5bmMgZnVuY3Rpb24gY2hlY2tUb2tlbih0b2tlbjogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHsKICBpZiAoIS9eW1x4MjEtXHg3ZV0rJC8udGVzdCh0b2tlbi50cmltKCkpKSB7CiAgICB0aHJvdyBuZXcgQXBpZnlFcnJvcigiVGhlIHRva2VuIGhhcyB1bmV4cGVjdGVkIGNoYXJhY3RlcnMuIENvcHkgaXQgYWdhaW4gd2l0aCB0aGUgY29weSBidXR0b24gaW4gQXBpZnkgQ29uc29sZS4iKTsKICB9CiAgY29uc3QgbWUgPSBhd2FpdCBjYWxsKGAvdXNlcnMvbWVgLCB7fSwgdG9rZW4pOwogIHJldHVybiBTdHJpbmcobWUuZGF0YS51c2VybmFtZSB8fCAieW91ciBhY2NvdW50Iik7Cn0KCi8qKiBXaGF0IHRoZSBydW4gY29zdCB0aGUgdXNlcjogcGF5LXBlci1ldmVudCBjaGFyZ2VzLCBwbHVzIHBsYXRmb3JtIHVzYWdlIHdoZW4gdGhlIHVzZXIgcGF5cyBpdC4gKi8KZXhwb3J0IGZ1bmN0aW9uIGNoYXJnZWRVc2QoZDogYW55KTogbnVtYmVyIHwgbnVsbCB7CiAgY29uc3QgdXNhZ2UgPSB0eXBlb2YgZC51c2FnZVRvdGFsVXNkID09PSAibnVtYmVyIiA/IGQudXNhZ2VUb3RhbFVzZCA6IG51bGw7CiAgY29uc3QgaW5mbyA9IGQucHJpY2luZ0luZm8gfHwge307CiAgaWYgKCFpbmZvLnByaWNpbmdNb2RlbCB8fCBpbmZvLnByaWNpbmdNb2RlbCA9PT0gIkZSRUUiKSByZXR1cm4gdXNhZ2U7CiAgaWYgKGluZm8ucHJpY2luZ01vZGVsICE9PSAiUEFZX1BFUl9FVkVOVCIpIHJldHVybiBudWxsOwogIGNvbnN0IGV2ZW50cyA9IGluZm8ucHJpY2luZ1BlckV2ZW50Py5hY3RvckNoYXJnZUV2ZW50cyB8fCB7fTsKICBsZXQgc3VtID0gMDsKICBmb3IgKGNvbnN0IFtuYW1lLCBuXSBvZiBPYmplY3QuZW50cmllcyhkLmNoYXJnZWRFdmVudENvdW50cyB8fCB7fSkpIHsKICAgIGlmICghTnVtYmVyKG4pKSBjb250aW51ZTsKICAgIGNvbnN0IGV2ID0gZXZlbnRzW25hbWVdOwogICAgLy8gVGllcmVkIHByaWNlcyBkZXBlbmQgb24gdGhlIHVzZXIncyBwbGFuLCB3aGljaCB0aGlzIHBhZ2UgZG9lcyBub3Qga25vdy4KICAgIGlmICghZXYgfHwgdHlwZW9mIGV2LmV2ZW50UHJpY2VVc2QgIT09ICJudW1iZXIiKSByZXR1cm4gbnVsbDsKICAgIHN1bSArPSBldi5ldmVudFByaWNlVXNkICogTnVtYmVyKG4pOwogIH0KICBpZiAoZC5wbGF0Zm9ybVVzYWdlQmlsbGluZ01vZGVsID09PSAiVVNFUiIgJiYgdXNhZ2UpIHN1bSArPSB1c2FnZTsKICByZXR1cm4gc3VtOwp9CgpmdW5jdGlvbiB0b1J1bihkOiBhbnkpOiBSdW4gewogIHJldHVybiB7CiAgICBpZDogU3RyaW5nKGQuaWQpLAogICAgc3RhdHVzOiBTdHJpbmcoZC5zdGF0dXMpLAogICAgZGF0YXNldElkOiBTdHJpbmcoZC5kZWZhdWx0RGF0YXNldElkKSwKICAgIGl0ZW1Db3VudDogMCwKICAgIHN0YXR1c01lc3NhZ2U6IFN0cmluZyhkLnN0YXR1c01lc3NhZ2UgfHwgIiIpLAogICAgdXNkOiBjaGFyZ2VkVXNkKGQpLAogICAgdXJsOiBgaHR0cHM6Ly9jb25zb2xlLmFwaWZ5LmNvbS92aWV3L3J1bnMvJHtkLmlkfWAsCiAgfTsKfQoKZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0UnVuKG5hbWU6IHN0cmluZywgaW5wdXQ6IEpzb24sIHRva2VuOiBzdHJpbmcsIG9wdHM6IHsgbWF4SXRlbXM6IG51bWJlcjsgbWF4VG90YWxDaGFyZ2VVc2Q6IG51bWJlciB9KTogUHJvbWlzZTxSdW4+IHsKICBjb25zdCBxID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh7IG1heEl0ZW1zOiBTdHJpbmcob3B0cy5tYXhJdGVtcyksIG1heFRvdGFsQ2hhcmdlVXNkOiBTdHJpbmcob3B0cy5tYXhUb3RhbENoYXJnZVVzZCkgfSk7CiAgY29uc3QgcmVzID0gYXdhaXQgY2FsbChgL2FjdHMvJHtPV05FUn1+JHtlbmNvZGVVUklDb21wb25lbnQobmFtZSl9L3J1bnM/JHtxfWAsIHsgbWV0aG9kOiAiUE9TVCIsIGJvZHk6IEpTT04uc3RyaW5naWZ5KGlucHV0KSB9LCB0b2tlbik7CiAgcmV0dXJuIHRvUnVuKHJlcy5kYXRhKTsKfQoKYXN5bmMgZnVuY3Rpb24gZGF0YXNldENvdW50KGRhdGFzZXRJZDogc3RyaW5nLCB0b2tlbjogc3RyaW5nKTogUHJvbWlzZTxudW1iZXI+IHsKICBjb25zdCByZXMgPSBhd2FpdCBjYWxsKGAvZGF0YXNldHMvJHtkYXRhc2V0SWR9YCwge30sIHRva2VuKTsKICByZXR1cm4gTnVtYmVyKHJlcy5kYXRhPy5pdGVtQ291bnQgfHwgMCk7Cn0KCi8qKiBSdW4gd2l0aCBpdHMgY3VycmVudCByZXN1bHQgY291bnQuIFJldHJpZXMgYSBmZXcgdGltZXMgb24gbmV0d29yayBlcnJvcnMuICovCmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRSdW4ocnVuSWQ6IHN0cmluZywgdG9rZW46IHN0cmluZywgd2FpdFNlY3MgPSAxMCk6IFByb21pc2U8UnVuPiB7CiAgZm9yIChsZXQgYXR0ZW1wdCA9IDE7IDsgYXR0ZW1wdCsrKSB7CiAgICB0cnkgewogICAgICBjb25zdCByZXMgPSBhd2FpdCBjYWxsKGAvYWN0b3ItcnVucy8ke3J1bklkfT93YWl0Rm9yRmluaXNoPSR7d2FpdFNlY3N9YCwge30sIHRva2VuKTsKICAgICAgY29uc3QgcnVuID0gdG9SdW4ocmVzLmRhdGEpOwogICAgICBydW4uaXRlbUNvdW50ID0gYXdhaXQgZGF0YXNldENvdW50KHJ1bi5kYXRhc2V0SWQsIHRva2VuKS5jYXRjaCgoKSA9PiAwKTsKICAgICAgcmV0dXJuIHJ1bjsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgY29uc3Qgc3RhdHVzID0gZSBpbnN0YW5jZW9mIEFwaWZ5RXJyb3IgPyBlLnN0YXR1cyA6IDA7CiAgICAgIGlmIChhdHRlbXB0ID49IDMgfHwgKHN0YXR1cyA+PSA0MDAgJiYgc3RhdHVzIDwgNTAwICYmIHN0YXR1cyAhPT0gNDI5KSkgdGhyb3cgZTsKICAgICAgYXdhaXQgbmV3IFByb21pc2UociA9PiBzZXRUaW1lb3V0KHIsIDIwMDAgKiBhdHRlbXB0KSk7CiAgICB9CiAgfQp9CgpleHBvcnQgYXN5bmMgZnVuY3Rpb24gYWJvcnRSdW4ocnVuSWQ6IHN0cmluZywgdG9rZW46IHN0cmluZyk6IFByb21pc2U8dm9pZD4gewogIGF3YWl0IGNhbGwoYC9hY3Rvci1ydW5zLyR7cnVuSWR9L2Fib3J0YCwgeyBtZXRob2Q6ICJQT1NUIiB9LCB0b2tlbik7Cn0KCi8qKiBMYXRlc3QgZmluaXNoZWQgcnVuIG9mIHRoaXMgc2NyYXBlciBpbiB0aGUgdXNlcidzIGFjY291bnQgdGhhdCBoYXMgcmVzdWx0cy4gKi8KZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxhc3RSdW4obmFtZTogc3RyaW5nLCB0b2tlbjogc3RyaW5nKTogUHJvbWlzZTxSdW4+IHsKICBjb25zdCByZXMgPSBhd2FpdCBjYWxsKGAvYWN0cy8ke09XTkVSfX4ke2VuY29kZVVSSUNvbXBvbmVudChuYW1lKX0vcnVucz9kZXNjPXRydWUmbGltaXQ9MTBgLCB7fSwgdG9rZW4pOwogIGZvciAoY29uc3QgciBvZiByZXMuZGF0YT8uaXRlbXMgfHwgW10pIHsKICAgIGlmICghVEVSTUlOQUwuaGFzKHIuc3RhdHVzKSkgY29udGludWU7CiAgICBjb25zdCBydW4gPSBhd2FpdCBnZXRSdW4oci5pZCwgdG9rZW4sIDApOwogICAgaWYgKHJ1bi5pdGVtQ291bnQgPiAwKSByZXR1cm4gcnVuOwogIH0KICB0aHJvdyBuZXcgQXBpZnlFcnJvcigiVGhlcmUgaXMgbm8gZmluaXNoZWQgcnVuIG9mIHRoaXMgc2NyYXBlciB3aXRoIHJlc3VsdHMgaW4geW91ciBBcGlmeSBhY2NvdW50IHlldC4gUHJlc3MgXHUyMDFjUnVuXHUyMDFkIGZpcnN0LiIsIDQwNCk7Cn0KCmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkYXRhc2V0SXRlbXMoZGF0YXNldElkOiBzdHJpbmcsIHRva2VuOiBzdHJpbmcsIGxpbWl0OiBudW1iZXIpOiBQcm9taXNlPEpzb25bXT4gewogIGNvbnN0IG91dDogSnNvbltdID0gW107CiAgbGV0IG9mZnNldCA9IDA7CiAgd2hpbGUgKG9mZnNldCA8IGxpbWl0KSB7CiAgICBjb25zdCB0YWtlID0gTWF0aC5taW4oMTAwMCwgbGltaXQgLSBvZmZzZXQpOwogICAgY29uc3QgcGFnZSA9IGF3YWl0IGNhbGwoYC9kYXRhc2V0cy8ke2RhdGFzZXRJZH0vaXRlbXM/c2tpcEhpZGRlbj10cnVlJmZvcm1hdD1qc29uJm9mZnNldD0ke29mZnNldH0mbGltaXQ9JHt0YWtlfWAsIHt9LCB0b2tlbik7CiAgICBpZiAoIUFycmF5LmlzQXJyYXkocGFnZSkpIGJyZWFrOwogICAgb2Zmc2V0ICs9IHBhZ2UubGVuZ3RoOwogICAgZm9yIChjb25zdCB4IG9mIHBhZ2UpIGlmICh4ICYmIHR5cGVvZiB4ID09PSAib2JqZWN0IiAmJiAhQXJyYXkuaXNBcnJheSh4KSkgb3V0LnB1c2goeCk7CiAgICBpZiAocGFnZS5sZW5ndGggPCB0YWtlKSBicmVhazsKICB9CiAgcmV0dXJuIG91dDsKfQoKLyoqIFN0YXJ0IGEgcnVuIGFuZCB3YWl0IGZvciBpdC4gb25VcGRhdGUocnVuKSBpcyBjYWxsZWQgd2hpbGUgd2FpdGluZy4gKi8KZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1bkFuZFdhaXQoCiAgbmFtZTogc3RyaW5nLCBpbnB1dDogSnNvbiwgdG9rZW46IHN0cmluZywKICBvcHRzOiB7IG1heEl0ZW1zOiBudW1iZXI7IG1heFRvdGFsQ2hhcmdlVXNkOiBudW1iZXI7IHRpbWVvdXRNcz86IG51bWJlciB9LAogIG9uVXBkYXRlOiAocnVuOiBSdW4pID0+IHZvaWQsIGlzQ2FuY2VsbGVkOiAoKSA9PiBib29sZWFuLAopOiBQcm9taXNlPFJ1bj4gewogIGxldCBydW4gPSBhd2FpdCBzdGFydFJ1bihuYW1lLCBpbnB1dCwgdG9rZW4sIG9wdHMpOwogIG9uVXBkYXRlKHJ1bik7CiAgY29uc3QgdXJsID0gcnVuLnVybDsKICBjb25zdCBkZWFkbGluZSA9IERhdGUubm93KCkgKyAob3B0cy50aW1lb3V0TXMgfHwgMTUgKiA2MCAqIDEwMDApOwogIHRyeSB7CiAgICB3aGlsZSAoIVRFUk1JTkFMLmhhcyhydW4uc3RhdHVzKSkgewogICAgICBpZiAoaXNDYW5jZWxsZWQoKSkgewogICAgICAgIHRyeSB7CiAgICAgICAgICBhd2FpdCBhYm9ydFJ1bihydW4uaWQsIHRva2VuKTsKICAgICAgICB9IGNhdGNoIHsKICAgICAgICAgIHRocm93IG5ldyBBcGlmeUVycm9yKCJDb3VsZCBub3Qgc3RvcCB0aGUgcnVuLiBJdCBtYXkgc3RpbGwgYmUgZ29pbmc6IG9wZW4gaXQgaW4gQXBpZnkgYW5kIHByZXNzIEFib3J0IHRoZXJlLiIsIDAsIHVybCk7CiAgICAgICAgfQogICAgICAgIHJ1biA9IGF3YWl0IGdldFJ1bihydW4uaWQsIHRva2VuLCAxMCkuY2F0Y2goKCkgPT4gcnVuKTsKICAgICAgICBydW4uc3RvcHBlZCA9IHRydWU7CiAgICAgICAgaWYgKCFydW4uaXRlbUNvdW50KSB0aHJvdyBuZXcgQXBpZnlFcnJvcigiVGhlIHJ1biB3YXMgc3RvcHBlZCBiZWZvcmUgaXQgcmV0dXJuZWQgYW55IHJlc3VsdHMuIEFwaWZ5IGJpbGxzIG9ubHkgdGhlIHBhcnQgdGhhdCBhbHJlYWR5IHJhbi4iLCAwLCB1cmwpOwogICAgICAgIHJldHVybiBydW47CiAgICAgIH0KICAgICAgaWYgKERhdGUubm93KCkgPiBkZWFkbGluZSkgewogICAgICAgIHRocm93IG5ldyBBcGlmeUVycm9yKCJUaGUgcnVuIGlzIHRha2luZyBsb25nZXIgdGhhbiAxNSBtaW51dGVzLiBJdCBrZWVwcyBnb2luZyBpbiBBcGlmeSB3aXRoaW4geW91ciBjb3N0IGNhcDsgcHJlc3MgXHUyMDFjTG9hZCBsYXN0IHJ1blx1MjAxZCBsYXRlci4iLCAwLCB1cmwpOwogICAgICB9CiAgICAgIHJ1biA9IGF3YWl0IGdldFJ1bihydW4uaWQsIHRva2VuLCA1KTsKICAgICAgb25VcGRhdGUocnVuKTsKICAgIH0KICB9IGNhdGNoIChlKSB7CiAgICBpZiAoZSBpbnN0YW5jZW9mIEFwaWZ5RXJyb3IgJiYgZS51cmwpIHRocm93IGU7CiAgICB0aHJvdyBuZXcgQXBpZnlFcnJvcihgJHtlIGluc3RhbmNlb2YgRXJyb3IgPyBlLm1lc3NhZ2UgOiBTdHJpbmcoZSl9IFRoZSBydW4gbWF5IHN0aWxsIGJlIGdvaW5nIGluIEFwaWZ5LmAsIGUgaW5zdGFuY2VvZiBBcGlmeUVycm9yID8gZS5zdGF0dXMgOiAwLCB1cmwpOwogIH0KICBpZiAocnVuLnN0YXR1cyAhPT0gIlNVQ0NFRURFRCIgJiYgcnVuLml0ZW1Db3VudCA9PT0gMCkgewogICAgdGhyb3cgbmV3IEFwaWZ5RXJyb3IoYFRoZSBydW4gZW5kZWQgd2l0aCBzdGF0dXMgJHtydW4uc3RhdHVzfSR7cnVuLnN0YXR1c01lc3NhZ2UgPyBgOiAke3J1bi5zdGF0dXNNZXNzYWdlfWAgOiAiIn0uYCwgMCwgcnVuLnVybCk7CiAgfQogIHJldHVybiBydW47Cn0KCi8vIC0tLS0tLS0tLS0gSW5wdXQgc2NoZW1hIFx1MjE5MiBmb3JtIC0tLS0tLS0tLS0KCmNvbnN0IExJTUlUX1dPUkQgPSBuZXcgU2V0KFsibWF4IiwgImxpbWl0IiwgImNvdW50IiwgIm51bWJlciIsICJudW0iLCAidG9wIiwgInRvdGFsIl0pOwpjb25zdCBMSU1JVF9OT1VOID0gL14oaXRlbXxyZXN1bHR8cm93fHJldmlld3xwb3N0fHZpZGVvfGpvYnxwcm9kdWN0fGNvbW1lbnR8bGlzdGluZ3xhcnRpY2xlfHN0b3J5fHN0b3JpZXN8dHdlZXR8cHJvZmlsZXxsZWFkfHBsYWNlfHJlY29yZHxwYWdlfGhvdGVsfGNvbXBhbnxjaGFubmVsfGVwaXNvZGV8cXVlc3Rpb258YW5zd2VyfHJlcG98ZXZlbnR8b2ZmZXJ8YWR8aW1hZ2V8c3RyZWFtfHNob3J0fHRyYWNrfGJvb2t8ZG9tYWlufGtleXdvcmR8dXJsfGxpbmt8ZW50cnxzbmFwc2hvdHxmaWxpbmd8YXdhcmR8cHJvcGVydHxjYXJ8dmVoaWNsZXxkZWFsfGFwcHxnYW1lfG1vdmllfHNob3d8c3VnZ2VzdGlvbnxwaW58dGhyZWFkKS87CmNvbnN0IE5PVF9MSU1JVCA9IG5ldyBTZXQoWyJwcmljZSIsICJyZXRyeSIsICJyZXRyaWVzIiwgImNvbmN1cnJlbmN5IiwgImFnZSIsICJkYXlzIiwgImRheSIsICJzaXplIiwgImRlcHRoIiwgInRpbWVvdXQiLCAibWVtb3J5IiwgImxlbmd0aCIsICJjaGFycyIsICJ3b3JkcyIsICJyYXRpbmciLCAic2NvcmUiLCAieWVhciIsICJ5ZWFycyIsICJkaXN0YW5jZSIsICJyYWRpdXMiLCAiZGVsYXkiLCAic2Vjb25kcyIsICJtcyIsICJieXRlcyIsICJtaW51dGVzIiwgImltcHJlc3Npb25zIiwgInZpZXdlcnMiLCAiZm9sbG93ZXJzIiwgInNhbGFyeSIsICJidWRnZXQiXSk7CgpmdW5jdGlvbiB3b3JkcyhrZXk6IHN0cmluZyk6IHN0cmluZ1tdIHsKICByZXR1cm4ga2V5LnJlcGxhY2UoLyhbYS16MC05XSkoW0EtWl0pL2csICIkMSAkMiIpLnRvTG93ZXJDYXNlKCkuc3BsaXQoL1teYS16XSsvKS5maWx0ZXIoQm9vbGVhbik7Cn0KCmV4cG9ydCBmdW5jdGlvbiBpc0xpbWl0S2V5KGtleTogc3RyaW5nKTogYm9vbGVhbiB7CiAgY29uc3QgdyA9IHdvcmRzKGtleSk7CiAgaWYgKHcuc29tZSh4ID0+IE5PVF9MSU1JVC5oYXMoeCkpKSByZXR1cm4gZmFsc2U7CiAgaWYgKHcubGVuZ3RoID09PSAxKSByZXR1cm4gd1swXSAhPT0gdW5kZWZpbmVkICYmIFsibGltaXQiLCAibWF4IiwgImNvdW50IiwgIm1heGl0ZW1zIl0uaW5jbHVkZXMod1swXSk7CiAgcmV0dXJuIHcuc29tZSh4ID0+IExJTUlUX1dPUkQuaGFzKHgpKSAmJiB3LnNvbWUoeCA9PiAhTElNSVRfV09SRC5oYXMoeCkgJiYgTElNSVRfTk9VTi50ZXN0KHgpKTsKfQoKZnVuY3Rpb24gc3RyaXAoaHRtbDogdW5rbm93bik6IHN0cmluZyB7CiAgcmV0dXJuIFN0cmluZyhodG1sIHx8ICIiKS5yZXBsYWNlKC88W14+XSs+L2csICIiKS5yZXBsYWNlKC8mbmJzcDsvZywgIiAiKS5yZXBsYWNlKC8mYW1wOy9nLCAiJiIpLnJlcGxhY2UoL1xzKy9nLCAiICIpLnRyaW0oKTsKfQoKZnVuY3Rpb24gY2xpcChzOiBzdHJpbmcsIG46IG51bWJlcik6IHN0cmluZyB7CiAgaWYgKHMubGVuZ3RoIDw9IG4pIHJldHVybiBzOwogIGNvbnN0IGN1dCA9IHMuc2xpY2UoMCwgbik7CiAgY29uc3QgZG90ID0gY3V0Lmxhc3RJbmRleE9mKCIuICIpOwogIHJldHVybiBkb3QgPiBuICogMC42ID8gY3V0LnNsaWNlKDAsIGRvdCArIDEpIDogYCR7Y3V0LnNsaWNlKDAsIGN1dC5sYXN0SW5kZXhPZigiICIpKX1cdTIwMjZgOwp9CgpmdW5jdGlvbiBraW5kT2YocDogU2NoZW1hUHJvcCk6IEZpZWxkS2luZCB7CiAgY29uc3QgdCA9IHAudHlwZTsKICBpZiAocC5lZGl0b3IgPT09ICJwcm94eSIpIHJldHVybiAianNvbiI7CiAgaWYgKHQgPT09ICJib29sZWFuIikgcmV0dXJuICJib29sZWFuIjsKICBpZiAodCA9PT0gImludGVnZXIiIHx8IHQgPT09ICJudW1iZXIiKSByZXR1cm4gIm51bWJlciI7CiAgaWYgKHQgPT09ICJzdHJpbmciKSB7CiAgICBpZiAocC5lbnVtPy5sZW5ndGgpIHJldHVybiAic2VsZWN0IjsKICAgIGlmIChwLmVkaXRvciA9PT0gInRleHRhcmVhIiB8fCBwLmVkaXRvciA9PT0gImphdmFzY3JpcHQiIHx8IHAuZWRpdG9yID09PSAicHl0aG9uIikgcmV0dXJuICJ0ZXh0YXJlYSI7CiAgICByZXR1cm4gInRleHQiOwogIH0KICBpZiAodCA9PT0gImFycmF5IikgewogICAgY29uc3QgaXQgPSBwLml0ZW1zIHx8IHt9OwogICAgaWYgKGl0LmVudW0/Lmxlbmd0aCkgcmV0dXJuICJtdWx0aXNlbGVjdCI7CiAgICBjb25zdCBwcm9wcyA9IGl0LnByb3BlcnRpZXMgYXMgSnNvbiB8IHVuZGVmaW5lZDsKICAgIGNvbnN0IHVybE9iamVjdHMgPSBpdC50eXBlID09PSAib2JqZWN0IiAmJiAhIXByb3BzICYmIGhhcyhwcm9wcywgInVybCIpICYmCiAgICAgIE9iamVjdC5rZXlzKHByb3BzKS5ldmVyeShrID0+IGsgPT09ICJ1cmwiIHx8ICEoaXQucmVxdWlyZWQgfHwgW10pLmluY2x1ZGVzKGspKTsKICAgIGlmIChwLmVkaXRvciA9PT0gInJlcXVlc3RMaXN0U291cmNlcyIgfHwgcC5lZGl0b3IgPT09ICJyZXF1ZXN0TGlzdCIgfHwgdXJsT2JqZWN0cykgcmV0dXJuICJ1cmxzIjsKICAgIGlmIChwLmVkaXRvciA9PT0gImpzb24iKSByZXR1cm4gaXQudHlwZSA9PT0gInN0cmluZyIgPyAibGlzdCIgOiAianNvbiI7CiAgICBpZiAocC5lZGl0b3IgPT09ICJzdHJpbmdMaXN0IiB8fCBwLmVkaXRvciA9PT0gInNlbGVjdCIgfHwgaXQudHlwZSA9PT0gInN0cmluZyIgfHwgKCFwLmVkaXRvciAmJiAhaXQudHlwZSkpIHJldHVybiAibGlzdCI7CiAgICByZXR1cm4gImpzb24iOwogIH0KICByZXR1cm4gImpzb24iOwp9CgpleHBvcnQgZnVuY3Rpb24gZXhhbXBsZU9mKGFjdG9yOiBBY3RvckluZm8pOiBKc29uIHsKICByZXR1cm4gKGhhcyhFWEFNUExFUywgYWN0b3IubmFtZSkgJiYgRVhBTVBMRVNbYWN0b3IubmFtZV0pIHx8IGFjdG9yLnBhZ2VFeGFtcGxlIHx8IHt9Owp9CgpleHBvcnQgZnVuY3Rpb24gZm9ybUZpZWxkcyhzY2hlbWE6IElucHV0U2NoZW1hIHwgbnVsbCwgZXhhbXBsZTogSnNvbiA9IHt9KTogRmllbGRbXSB7CiAgaWYgKCFzY2hlbWEpIHJldHVybiBbXTsKICBjb25zdCByZXF1aXJlZCA9IG5ldyBTZXQoc2NoZW1hLnJlcXVpcmVkIHx8IFtdKTsKICBsZXQgaW5BZHZhbmNlZCA9IGZhbHNlOwogIGNvbnN0IG91dDogKEZpZWxkICYgeyBhZHY6IGJvb2xlYW4gfSlbXSA9IFtdOwogIGZvciAoY29uc3QgW2tleSwgcF0gb2YgT2JqZWN0LmVudHJpZXMoc2NoZW1hLnByb3BlcnRpZXMpKSB7CiAgICBpZiAocC5pc1NlY3JldCkgY29udGludWU7CiAgICBpZiAocC5zZWN0aW9uQ2FwdGlvbiAmJiAvYWR2YW5jZWR8cHJveHl8ZGV2ZWxvcGVyfGRlYnVnfG9wdGlvbmFsL2kudGVzdChwLnNlY3Rpb25DYXB0aW9uKSkgaW5BZHZhbmNlZCA9IHRydWU7CiAgICBjb25zdCBraW5kID0ga2luZE9mKHApOwogICAgY29uc3QgdmFscyA9IChraW5kID09PSAibXVsdGlzZWxlY3QiID8gcC5pdGVtcz8uZW51bSA6IHAuZW51bSkgfHwgW107CiAgICBjb25zdCB0aXRsZXMgPSAoa2luZCA9PT0gIm11bHRpc2VsZWN0IiA/IHAuaXRlbXM/LmVudW1UaXRsZXMgOiBwLmVudW1UaXRsZXMpIHx8IFtdOwogICAgb3V0LnB1c2goewogICAgICBrZXksCiAgICAgIGxhYmVsOiBwLnRpdGxlIHx8IGtleSwKICAgICAga2luZCwKICAgICAgaGVscDogY2xpcChzdHJpcChwLmRlc2NyaXB0aW9uKSwgMjIwKSwKICAgICAgcmVxdWlyZWQ6IHJlcXVpcmVkLmhhcyhrZXkpLAogICAgICBvcHRpb25zOiB2YWxzLm1hcCgodiwgaSkgPT4gKHsgdmFsdWU6IFN0cmluZyh2KSwgbGFiZWw6IFN0cmluZyh0aXRsZXNbaV0gPz8gdikgfSkpLAogICAgICAuLi4ocC5taW5pbXVtICE9PSB1bmRlZmluZWQgPyB7IG1pbjogcC5taW5pbXVtIH0gOiB7fSksCiAgICAgIC4uLihwLm1heGltdW0gIT09IHVuZGVmaW5lZCA/IHsgbWF4OiBwLm1heGltdW0gfSA6IHt9KSwKICAgICAgaXNMaW1pdDoga2luZCA9PT0gIm51bWJlciIgJiYgaXNMaW1pdEtleShrZXkpLAogICAgICBhZHZhbmNlZDogZmFsc2UsCiAgICAgIGFkdjogKGluQWR2YW5jZWQgfHwgcC5lZGl0b3IgPT09ICJwcm94eSIgfHwgL2RlYnVnfHByb3h5fGNvb2tpZXxzZXNzaW9ufGNvbmN1cnJlbmN5fHRpbWVvdXR8d2ViaG9va3xzbmFwc2hvdC9pLnRlc3Qoa2V5KSkgJiYgIXJlcXVpcmVkLmhhcyhrZXkpLAogICAgfSk7CiAgfQogIGNvbnN0IG1haW4gPSAoZjogRmllbGQgJiB7IGFkdjogYm9vbGVhbiB9KSA9PiAhZi5hZHYgJiYgKGYucmVxdWlyZWQgfHwgaGFzKGV4YW1wbGUsIGYua2V5KSB8fCBmLmlzTGltaXQpOwogIGNvbnN0IGFueU1haW4gPSBvdXQuc29tZShtYWluKTsKICByZXR1cm4gb3V0Lm1hcCgoeyBhZHYsIC4uLmYgfSkgPT4gKHsgLi4uZiwgYWR2YW5jZWQ6IGFueU1haW4gPyAhbWFpbih7IC4uLmYsIGFkdiB9KSA6IGFkdiB9KSk7Cn0KCi8qKiBTdGFydGluZyBpbnB1dDogdGVzdGVkIGV4YW1wbGUsIGVsc2UgdGhlIHBhZ2UgZXhhbXBsZSwgZWxzZSBwcmVmaWxsL2RlZmF1bHQuIExpbWl0cyBjYXBwZWQgc21hbGwuICovCmV4cG9ydCBmdW5jdGlvbiBpbml0aWFsSW5wdXQoYWN0b3I6IEFjdG9ySW5mbyk6IEpzb24gewogIGNvbnN0IGV4YW1wbGUgPSBleGFtcGxlT2YoYWN0b3IpOwogIGNvbnN0IGlucHV0OiBKc29uID0gY2xvbmUoZXhhbXBsZSk7CiAgY29uc3QgcHJvcHMgPSBhY3Rvci5zY2hlbWE/LnByb3BlcnRpZXM7CiAgaWYgKCFwcm9wcykgcmV0dXJuIGlucHV0OwogIGZvciAoY29uc3QgW2tleSwgcF0gb2YgT2JqZWN0LmVudHJpZXMocHJvcHMpKSB7CiAgICBpZiAoaGFzKGlucHV0LCBrZXkpIHx8IHAuaXNTZWNyZXQpIGNvbnRpbnVlOwogICAgY29uc3QgdiA9IHAucHJlZmlsbCAhPT0gdW5kZWZpbmVkID8gcC5wcmVmaWxsIDogcC5kZWZhdWx0OwogICAgaWYgKHYgIT09IHVuZGVmaW5lZCkgaW5wdXRba2V5XSA9IGNsb25lKHYpOwogIH0KICBmb3IgKGNvbnN0IFtrZXksIHBdIG9mIE9iamVjdC5lbnRyaWVzKHByb3BzKSkgewogICAgaWYgKChwLnR5cGUgPT09ICJpbnRlZ2VyIiB8fCBwLnR5cGUgPT09ICJudW1iZXIiKSAmJiBpc0xpbWl0S2V5KGtleSkpIHsKICAgICAgY29uc3QgY3VyID0gdHlwZW9mIGlucHV0W2tleV0gPT09ICJudW1iZXIiID8gKGlucHV0W2tleV0gYXMgbnVtYmVyKSA6IHVuZGVmaW5lZDsKICAgICAgY29uc3QgbWluID0gcC5taW5pbXVtID8/IDE7CiAgICAgIC8vIEEgMCBzZXQgYnkgdGhlIGV4YW1wbGUgbWVhbnMgIm5vbmUiIChmb3IgZXhhbXBsZSBubyBjb21tZW50cyk7IGtlZXAgaXQuCiAgICAgIGNvbnN0IHVuc2V0ID0gY3VyID09PSB1bmRlZmluZWQgfHwgKGN1ciA9PT0gMCAmJiAhaGFzKGV4YW1wbGUsIGtleSkpOwogICAgICBpZiAodW5zZXQgfHwgKGN1ciAhPT0gdW5kZWZpbmVkICYmIGN1ciA+IERFRkFVTFRfTElNSVQpKSB7CiAgICAgICAgaW5wdXRba2V5XSA9IE1hdGgubWF4KG1pbiwgTWF0aC5taW4oREVGQVVMVF9MSU1JVCwgcC5tYXhpbXVtID8/IERFRkFVTFRfTElNSVQpKTsKICAgICAgfQogICAgfQogIH0KICByZXR1cm4gaW5wdXQ7Cn0KCmV4cG9ydCBmdW5jdGlvbiBpbnB1dFNvdXJjZShhY3RvcjogQWN0b3JJbmZvKTogc3RyaW5nIHsKICBpZiAoaGFzKEVYQU1QTEVTLCBhY3Rvci5uYW1lKSkgcmV0dXJuICJhIHRlc3RlZCBleGFtcGxlIjsKICBpZiAoT2JqZWN0LmtleXMoYWN0b3IucGFnZUV4YW1wbGUgfHwge30pLmxlbmd0aCkgcmV0dXJuICJ0aGUgZXhhbXBsZSBmcm9tIHRoZSBzY3JhcGVyJ3MgcGFnZSI7CiAgcmV0dXJuICJ0aGUgZGVmYXVsdCB2YWx1ZXMiOwp9Cgpjb25zdCBpc0VtcHR5ID0gKHY6IHVua25vd24pID0+IHYgPT09ICIiIHx8IHYgPT09IG51bGwgfHwgdiA9PT0gdW5kZWZpbmVkIHx8IChBcnJheS5pc0FycmF5KHYpICYmIHYubGVuZ3RoID09PSAwKTsKCmV4cG9ydCBmdW5jdGlvbiBjbGVhbklucHV0KGlucHV0OiBKc29uLCBmaWVsZHM6IEZpZWxkW10pOiBKc29uIHsKICBjb25zdCByZXEgPSBuZXcgU2V0KGZpZWxkcy5maWx0ZXIoZiA9PiBmLnJlcXVpcmVkKS5tYXAoZiA9PiBmLmtleSkpOwogIGNvbnN0IG91dDogSnNvbiA9IHt9OwogIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKGlucHV0KSkgewogICAgaWYgKCFyZXEuaGFzKGspICYmIGlzRW1wdHkodikpIGNvbnRpbnVlOwogICAgb3V0W2tdID0gdjsKICB9CiAgcmV0dXJuIG91dDsKfQoKZXhwb3J0IGZ1bmN0aW9uIG1pc3NpbmdSZXF1aXJlZChpbnB1dDogSnNvbiwgZmllbGRzOiBGaWVsZFtdKTogc3RyaW5nW10gewogIHJldHVybiBmaWVsZHMuZmlsdGVyKGYgPT4gZi5yZXF1aXJlZCAmJiBpc0VtcHR5KGlucHV0W2Yua2V5XSkpLm1hcChmID0+IGYubGFiZWwpOwp9CgovLyAtLS0tLS0tLS0tIEl0ZW1zIFx1MjE5MiB0YWJsZSwgQ1NWIC0tLS0tLS0tLS0KCmV4cG9ydCB0eXBlIENlbGwgPSBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgbnVsbDsKZXhwb3J0IHR5cGUgUm93ID0gUmVjb3JkPHN0cmluZywgQ2VsbD47CgovKiogRmxhdHRlbiBvbmUgaXRlbTogbmVzdGVkIG9iamVjdHMgdG8gImEuYiIga2V5cyAoMiBsZXZlbHMpLCBsaXN0cyBvZiBwbGFpbiB2YWx1ZXMgam9pbmVkLCB0aGUgcmVzdCBhcyBKU09OLiAqLwpleHBvcnQgZnVuY3Rpb24gZmxhdHRlbkl0ZW0oaXRlbTogSnNvbik6IFJvdyB7CiAgY29uc3Qgb3V0OiBSb3cgPSBPYmplY3QuY3JlYXRlKG51bGwpOwogIGNvbnN0IHB1dCA9IChwcmVmaXg6IHN0cmluZywgdjogdW5rbm93biwgZGVwdGg6IG51bWJlcikgPT4gewogICAgaWYgKHYgPT09IG51bGwgfHwgdiA9PT0gdW5kZWZpbmVkKSB7IG91dFtwcmVmaXhdID0gbnVsbDsgcmV0dXJuOyB9CiAgICBpZiAoQXJyYXkuaXNBcnJheSh2KSkgewogICAgICBvdXRbcHJlZml4XSA9IHYuZXZlcnkoeCA9PiB4ID09PSBudWxsIHx8IFsic3RyaW5nIiwgIm51bWJlciIsICJib29sZWFuIl0uaW5jbHVkZXModHlwZW9mIHgpKQogICAgICAgID8gdi5maWx0ZXIoeCA9PiB4ICE9PSBudWxsKS5qb2luKCIsICIpCiAgICAgICAgOiBKU09OLnN0cmluZ2lmeSh2KTsKICAgICAgcmV0dXJuOwogICAgfQogICAgaWYgKHR5cGVvZiB2ID09PSAib2JqZWN0IikgewogICAgICBpZiAoZGVwdGggPj0gMikgeyBvdXRbcHJlZml4XSA9IEpTT04uc3RyaW5naWZ5KHYpOyByZXR1cm47IH0KICAgICAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKHYgYXMgSnNvbik7CiAgICAgIGlmICgha2V5cy5sZW5ndGgpIHsgb3V0W3ByZWZpeF0gPSBudWxsOyByZXR1cm47IH0KICAgICAgZm9yIChjb25zdCBrIG9mIGtleXMpIHB1dChgJHtwcmVmaXh9LiR7a31gLCAodiBhcyBKc29uKVtrXSwgZGVwdGggKyAxKTsKICAgICAgcmV0dXJuOwogICAgfQogICAgb3V0W3ByZWZpeF0gPSB2IGFzIENlbGw7CiAgfTsKICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyhpdGVtKSkgcHV0KGssIHYsIDApOwogIHJldHVybiBvdXQ7Cn0KCmV4cG9ydCBjb25zdCBNQVhfQ09MVU1OUyA9IDgwOwoKLyoqIENvbHVtbiBrZXlzIGluIG9yZGVyIG9mIGZpcnN0IGFwcGVhcmFuY2UsIGNhcHBlZCBhdCBNQVhfQ09MVU1OUyAodGhlIG1vc3QgZmlsbGVkIGFyZSBrZXB0KS4gKi8KZXhwb3J0IGZ1bmN0aW9uIHBsYW5Db2x1bW5zKHJvd3M6IFJvd1tdKTogc3RyaW5nW10gewogIGNvbnN0IGZpbGxlZCA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7CiAgZm9yIChjb25zdCByIG9mIHJvd3MpIHsKICAgIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKHIpKSB7CiAgICAgIGZpbGxlZC5zZXQoaywgKGZpbGxlZC5nZXQoaykgfHwgMCkgKyAodiA9PT0gbnVsbCB8fCB2ID09PSAiIiA/IDAgOiAxKSk7CiAgICB9CiAgfQogIGNvbnN0IG9yZGVyID0gWy4uLmZpbGxlZC5rZXlzKCldOwogIGlmIChvcmRlci5sZW5ndGggPD0gTUFYX0NPTFVNTlMpIHJldHVybiBvcmRlcjsKICBjb25zdCBrZWVwID0gbmV3IFNldChbLi4ub3JkZXJdLnNvcnQoKGEsIGIpID0+IGZpbGxlZC5nZXQoYikhIC0gZmlsbGVkLmdldChhKSEpLnNsaWNlKDAsIE1BWF9DT0xVTU5TKSk7CiAgcmV0dXJuIG9yZGVyLmZpbHRlcihrID0+IGtlZXAuaGFzKGspKTsKfQoKZnVuY3Rpb24gY3N2Q2VsbCh2OiBDZWxsKTogc3RyaW5nIHsKICBpZiAodiA9PT0gbnVsbCB8fCB2ID09PSB1bmRlZmluZWQpIHJldHVybiAiIjsKICBsZXQgcyA9IFN0cmluZyh2KTsKICAvLyBTdG9wIHNwcmVhZHNoZWV0IGFwcHMgZnJvbSBydW5uaW5nIHRleHQgYXMgYSBmb3JtdWxhLgogIGlmICh0eXBlb2YgdiA9PT0gInN0cmluZyIgJiYgL15bPStcLUBcdFxyXS8udGVzdChzKSkgcyA9IGAnJHtzfWA7CiAgcmV0dXJuIC9bIixcblxyXS8udGVzdChzKSA/IGAiJHtzLnJlcGxhY2UoLyIvZywgJyIiJyl9ImAgOiBzOwp9CgpleHBvcnQgZnVuY3Rpb24gdG9Dc3Yocm93czogUm93W10sIGNvbHM6IHN0cmluZ1tdKTogc3RyaW5nIHsKICBjb25zdCBsaW5lcyA9IFtjb2xzLm1hcChjID0+IGNzdkNlbGwoYykpLmpvaW4oIiwiKV07CiAgZm9yIChjb25zdCByIG9mIHJvd3MpIGxpbmVzLnB1c2goY29scy5tYXAoYyA9PiBjc3ZDZWxsKHJbY10gPz8gbnVsbCkpLmpvaW4oIiwiKSk7CiAgcmV0dXJuIGBcdWZlZmYke2xpbmVzLmpvaW4oIlxyXG4iKX1cclxuYDsKfQoKZXhwb3J0IGZ1bmN0aW9uIGZtdFVzZChuOiBudW1iZXIgfCBudWxsIHwgdW5kZWZpbmVkKTogc3RyaW5nIHsKICBpZiAobiA9PSBudWxsIHx8IE51bWJlci5pc05hTihuKSkgcmV0dXJuICIiOwogIGlmIChuID09PSAwKSByZXR1cm4gIiQwIjsKICBpZiAobiA8IDAuMDAwMSkgcmV0dXJuICJ1bmRlciAkMC4wMDAxIjsKICBpZiAobiA8IDAuMDEpIHJldHVybiBgJCR7bi50b0ZpeGVkKDQpLnJlcGxhY2UoLzArJC8sICIiKX1gOwogIHJldHVybiBgJCR7bi50b0ZpeGVkKDIpfWA7Cn0KCmV4cG9ydCBmdW5jdGlvbiBlc3RpbWF0ZShhY3RvcjogeyBwcmljZTogbnVtYmVyIHwgbnVsbDsgdW5pdDogc3RyaW5nIH0sIG1heEl0ZW1zOiBudW1iZXIpOiBzdHJpbmcgewogIGlmIChhY3Rvci5wcmljZSA9PSBudWxsKSByZXR1cm4gIiI7CiAgcmV0dXJuIGBBYm91dCAke2ZtdFVzZChhY3Rvci5wcmljZSl9IHBlciAke2FjdG9yLnVuaXR9IG9uIHRoZSBBcGlmeSBmcmVlIHBsYW4sIHNvIHJvdWdobHkgJHtmbXRVc2QoYWN0b3IucHJpY2UgKiBtYXhJdGVtcyl9IGZvciAke21heEl0ZW1zfSByZXN1bHRzLmA7Cn0KCmV4cG9ydCBmdW5jdGlvbiBmaWxlTmFtZShhY3Rvck5hbWU6IHN0cmluZywgZXh0OiBzdHJpbmcpOiBzdHJpbmcgewogIGNvbnN0IGQgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkuc2xpY2UoMCwgMTYpLnJlcGxhY2UoL1s6VF0vZywgIi0iKTsKICByZXR1cm4gYCR7YWN0b3JOYW1lfS0ke2R9LiR7ZXh0fWA7Cn0KCi8vIC0tLS0tLS0tLS0gUmFpbHdheSBzZXJ2ZXIgLS0tLS0tLS0tLQovLyBZb3VyIEFwaWZ5IHRva2VuIGxpdmVzIG9ubHkgaW4gdGhlIEFQSUZZX1RPS0VOIHZhcmlhYmxlIG9mIHlvdXIgUmFpbHdheSBzZXJ2aWNlLgovLyBJdCBuZXZlciBnb2VzIHRvIHRoZSBicm93c2VyOiB0aGUgcGFnZSB0YWxrcyB0byB0aGlzIHNlcnZlciwgdGhlIHNlcnZlciB0YWxrcyB0byBBcGlmeS4KCmNvbnN0IFRPS0VOID0gU3RyaW5nKHByb2Nlc3MuZW52LkFQSUZZX1RPS0VOIHx8ICIiKS50cmltKCk7CmNvbnN0IFBBU1NXT1JEID0gU3RyaW5nKHByb2Nlc3MuZW52LkFDQ0VTU19QQVNTV09SRCB8fCAiIikudHJpbSgpOwpjb25zdCBQT1JUID0gTnVtYmVyKHByb2Nlc3MuZW52LlBPUlQgfHwgMzAwMCk7CmNvbnN0IElEX1JFID0gL15bQS1aYS16MC05XXs4LDQwfSQvOwoKbGV0IGNhdGFsb2dDYWNoZTogeyBhdDogbnVtYmVyOyBsaXN0OiBDYXRhbG9nQWN0b3JbXSB9IHwgbnVsbCA9IG51bGw7CmFzeW5jIGZ1bmN0aW9uIGNhdGFsb2coKTogUHJvbWlzZTxDYXRhbG9nQWN0b3JbXT4gewogIGlmIChjYXRhbG9nQ2FjaGUgJiYgRGF0ZS5ub3coKSAtIGNhdGFsb2dDYWNoZS5hdCA8IDEwICogNjAgKiAxMDAwKSByZXR1cm4gY2F0YWxvZ0NhY2hlLmxpc3Q7CiAgY29uc3QgbGlzdCA9IGF3YWl0IGZldGNoQ2F0YWxvZygpOwogIGNhdGFsb2dDYWNoZSA9IHsgYXQ6IERhdGUubm93KCksIGxpc3QgfTsKICByZXR1cm4gbGlzdDsKfQoKZnVuY3Rpb24gc2FtZVRleHQoYTogc3RyaW5nLCBiOiBzdHJpbmcpOiBib29sZWFuIHsKICBjb25zdCB4ID0gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKGEpOwogIGNvbnN0IHkgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoYik7CiAgbGV0IGRpZmYgPSB4Lmxlbmd0aCBeIHkubGVuZ3RoOwogIGZvciAobGV0IGkgPSAwOyBpIDwgTWF0aC5tYXgoeC5sZW5ndGgsIHkubGVuZ3RoKTsgaSsrKSBkaWZmIHw9ICh4W2ldID8/IDApIF4gKHlbaV0gPz8gMCk7CiAgcmV0dXJuIGRpZmYgPT09IDA7Cn0KCmZ1bmN0aW9uIGF1dGhvcml6ZWQocmVxOiBSZXF1ZXN0KTogYm9vbGVhbiB7CiAgaWYgKCFQQVNTV09SRCkgcmV0dXJuIHRydWU7CiAgY29uc3QgaCA9IHJlcS5oZWFkZXJzLmdldCgiYXV0aG9yaXphdGlvbiIpIHx8ICIiOwogIGlmICghaC5zdGFydHNXaXRoKCJCYXNpYyAiKSkgcmV0dXJuIGZhbHNlOwogIGxldCBkZWNvZGVkID0gIiI7CiAgdHJ5IHsgZGVjb2RlZCA9IGF0b2IoaC5zbGljZSg2KSk7IH0gY2F0Y2ggeyByZXR1cm4gZmFsc2U7IH0KICBjb25zdCBwYXNzID0gZGVjb2RlZC5zbGljZShkZWNvZGVkLmluZGV4T2YoIjoiKSArIDEpOwogIHJldHVybiBzYW1lVGV4dChwYXNzLCBQQVNTV09SRCk7Cn0KCmNvbnN0IFNFQ1VSSVRZX0hFQURFUlM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7CiAgIlgtQ29udGVudC1UeXBlLU9wdGlvbnMiOiAibm9zbmlmZiIsCiAgIlJlZmVycmVyLVBvbGljeSI6ICJuby1yZWZlcnJlciIsCiAgIlgtRnJhbWUtT3B0aW9ucyI6ICJERU5ZIiwKICAiQ2FjaGUtQ29udHJvbCI6ICJuby1zdG9yZSIsCn07CgpmdW5jdGlvbiBqc29uKGRhdGE6IHVua25vd24sIHN0YXR1cyA9IDIwMCk6IFJlc3BvbnNlIHsKICByZXR1cm4gbmV3IFJlc3BvbnNlKEpTT04uc3RyaW5naWZ5KGRhdGEpLCB7IHN0YXR1cywgaGVhZGVyczogeyAuLi5TRUNVUklUWV9IRUFERVJTLCAiQ29udGVudC1UeXBlIjogImFwcGxpY2F0aW9uL2pzb247IGNoYXJzZXQ9dXRmLTgiIH0gfSk7Cn0KCmZ1bmN0aW9uIGZhaWwoZTogdW5rbm93bik6IFJlc3BvbnNlIHsKICBjb25zdCBtc2cgPSBlIGluc3RhbmNlb2YgRXJyb3IgPyBlLm1lc3NhZ2UgOiBTdHJpbmcoZSk7CiAgY29uc3Qgc3RhdHVzID0gZSBpbnN0YW5jZW9mIEFwaWZ5RXJyb3IgJiYgZS5zdGF0dXMgPj0gNDAwICYmIGUuc3RhdHVzIDwgNjAwID8gZS5zdGF0dXMgOiA0MDA7CiAgcmV0dXJuIGpzb24oeyBlcnJvcjogbXNnLCB1cmw6IGUgaW5zdGFuY2VvZiBBcGlmeUVycm9yID8gZS51cmwgOiB1bmRlZmluZWQgfSwgc3RhdHVzKTsKfQoKZnVuY3Rpb24gbmVlZFRva2VuKCk6IHZvaWQgewogIGlmICghVE9LRU4pIHRocm93IG5ldyBBcGlmeUVycm9yKCJBUElGWV9UT0tFTiBpcyBlbXB0eS4gT3BlbiB5b3VyIFJhaWx3YXkgc2VydmljZSDigJrDnMOtIFZhcmlhYmxlcywgcGFzdGUgeW91ciBBcGlmeSBBUEkgdG9rZW4gaW50byBBUElGWV9UT0tFTiBhbmQgcmVkZXBsb3kuIiwgNDEyKTsKfQoKZnVuY3Rpb24gbmVlZFBhc3N3b3JkKCk6IHZvaWQgewogIGlmICghUEFTU1dPUkQpIHRocm93IG5ldyBBcGlmeUVycm9yKCJBQ0NFU1NfUEFTU1dPUkQgaXMgZW1wdHksIHNvIGFueW9uZSB3aXRoIHRoaXMgbGluayBjb3VsZCBzcGVuZCB5b3VyIEFwaWZ5IGNyZWRpdC4gU2V0IEFDQ0VTU19QQVNTV09SRCBpbiBSYWlsd2F5IOKAmsOcw60gVmFyaWFibGVzIGZpcnN0LiIsIDQxMik7Cn0KCmZ1bmN0aW9uIGNsYW1wTnVtKHY6IHVua25vd24sIG1pbjogbnVtYmVyLCBtYXg6IG51bWJlciwgZGVmOiBudW1iZXIpOiBudW1iZXIgewogIGlmICh2ID09PSBudWxsIHx8IHYgPT09IHVuZGVmaW5lZCB8fCB2ID09PSAiIikgcmV0dXJuIGRlZjsKICBjb25zdCBuID0gTnVtYmVyKHYpOwogIGlmICghTnVtYmVyLmlzRmluaXRlKG4pKSByZXR1cm4gZGVmOwogIHJldHVybiBNYXRoLm1pbihtYXgsIE1hdGgubWF4KG1pbiwgbikpOwp9Cgphc3luYyBmdW5jdGlvbiBoYW5kbGUocmVxOiBSZXF1ZXN0KTogUHJvbWlzZTxSZXNwb25zZT4gewogIGNvbnN0IHVybCA9IG5ldyBVUkwocmVxLnVybCk7CiAgY29uc3QgcCA9IHVybC5wYXRobmFtZTsKICBpZiAocCA9PT0gIi9oZWFsdGgiKSByZXR1cm4gbmV3IFJlc3BvbnNlKCJvayIsIHsgaGVhZGVyczogU0VDVVJJVFlfSEVBREVSUyB9KTsKICBpZiAoIWF1dGhvcml6ZWQocmVxKSkgewogICAgcmV0dXJuIG5ldyBSZXNwb25zZSgiUGFzc3dvcmQgcmVxdWlyZWQuIFVzZSBhbnkgdXNlciBuYW1lIGFuZCB0aGUgQUNDRVNTX1BBU1NXT1JEIGZyb20geW91ciBSYWlsd2F5IFZhcmlhYmxlcy4iLCB7CiAgICAgIHN0YXR1czogNDAxLCBoZWFkZXJzOiB7IC4uLlNFQ1VSSVRZX0hFQURFUlMsICJXV1ctQXV0aGVudGljYXRlIjogJ0Jhc2ljIHJlYWxtPSJBcGlmeSBTY3JhcGVyIFJ1bm5lciIsIGNoYXJzZXQ9IlVURi04IicgfSwKICAgIH0pOwogIH0KICB0cnkgewogICAgaWYgKHAgPT09ICIvIiAmJiByZXEubWV0aG9kID09PSAiR0VUIikgewogICAgICByZXR1cm4gbmV3IFJlc3BvbnNlKFBBR0UsIHsgaGVhZGVyczogeyAuLi5TRUNVUklUWV9IRUFERVJTLCAiQ29udGVudC1UeXBlIjogInRleHQvaHRtbDsgY2hhcnNldD11dGYtOCIgfSB9KTsKICAgIH0KICAgIGlmIChwID09PSAiL2FwaS9zdGF0dXMiKSB7CiAgICAgIGxldCBhY2NvdW50ID0gIiIsIGVycm9yID0gIiI7CiAgICAgIGlmIChUT0tFTikgeyB0cnkgeyBhY2NvdW50ID0gYXdhaXQgY2hlY2tUb2tlbihUT0tFTik7IH0gY2F0Y2ggKGUpIHsgZXJyb3IgPSBlIGluc3RhbmNlb2YgRXJyb3IgPyBlLm1lc3NhZ2UgOiBTdHJpbmcoZSk7IH0gfQogICAgICByZXR1cm4ganNvbih7IHRva2VuU2V0OiAhIVRPS0VOLCBwYXNzd29yZFNldDogISFQQVNTV09SRCwgYWNjb3VudCwgZXJyb3IsIHNpdGU6IHNpdGVVcmwoKSwgbWF4SXRlbXM6IE1BWF9JVEVNUywgbWF4VXNkOiBNQVhfVVNEIH0pOwogICAgfQogICAgaWYgKHAgPT09ICIvYXBpL2FjdG9ycyIpIHsKICAgICAgY29uc3QgcSA9IHVybC5zZWFyY2hQYXJhbXMuZ2V0KCJxIikgfHwgIiI7CiAgICAgIGNvbnN0IGxpc3QgPSBzZWFyY2hDYXRhbG9nKGF3YWl0IGNhdGFsb2coKSwgcSk7CiAgICAgIHJldHVybiBqc29uKHsgdG90YWw6IGxpc3QubGVuZ3RoLCBpdGVtczogbGlzdC5tYXAoYSA9PiAoeyAuLi5hLCB0ZXN0ZWQ6IGhhcyhFWEFNUExFUywgYS5uYW1lKSwgc2l0ZTogc2l0ZVVybChhLm5hbWUpIH0pKSB9KTsKICAgIH0KICAgIGlmIChwID09PSAiL2FwaS9hY3RvciIpIHsKICAgICAgY29uc3QgYSA9IGF3YWl0IGZldGNoQWN0b3IodXJsLnNlYXJjaFBhcmFtcy5nZXQoIm5hbWUiKSB8fCAiIik7CiAgICAgIGNvbnN0IGlucHV0ID0gaW5pdGlhbElucHV0KGEpOwogICAgICBjb25zdCBmaWVsZHMgPSBmb3JtRmllbGRzKGEuc2NoZW1hLCBleGFtcGxlT2YoYSkpLm1hcChmID0+ICh7IGtleTogZi5rZXksIGxhYmVsOiBmLmxhYmVsLCBoZWxwOiBmLmhlbHAsIHJlcXVpcmVkOiBmLnJlcXVpcmVkLCBraW5kOiBmLmtpbmQsIG9wdGlvbnM6IGYub3B0aW9ucy5zbGljZSgwLCAzMCkubWFwKG8gPT4gby52YWx1ZSkgfSkpOwogICAgICByZXR1cm4ganNvbih7CiAgICAgICAgbmFtZTogYS5uYW1lLCB0aXRsZTogYS50aXRsZSwgZGVzY3JpcHRpb246IGEuZGVzY3JpcHRpb24sIHBpY3R1cmU6IGEucGljdHVyZSwgcHJpY2U6IGEucHJpY2UsIHVuaXQ6IGEudW5pdCwKICAgICAgICBpbnB1dCwgc291cmNlOiBpbnB1dFNvdXJjZShhKSwgZmllbGRzLCBzdG9yZTogc3RvcmVVcmwoYS5uYW1lKSwgc2l0ZTogc2l0ZVVybChhLm5hbWUpLCBlc3RpbWF0ZTogZXN0aW1hdGUoYSwgREVGQVVMVF9MSU1JVCksCiAgICAgIH0pOwogICAgfQogICAgaWYgKHAgPT09ICIvYXBpL3J1biIgJiYgcmVxLm1ldGhvZCA9PT0gIlBPU1QiKSB7CiAgICAgIG5lZWRUb2tlbigpOyBuZWVkUGFzc3dvcmQoKTsKICAgICAgY29uc3QgYm9keTogYW55ID0gYXdhaXQgcmVxLmpzb24oKS5jYXRjaCgoKSA9PiBudWxsKTsKICAgICAgaWYgKCFib2R5IHx8IHR5cGVvZiBib2R5ICE9PSAib2JqZWN0IikgdGhyb3cgbmV3IEFwaWZ5RXJyb3IoIkJhZCByZXF1ZXN0LiIpOwogICAgICBjb25zdCBhID0gYXdhaXQgZmV0Y2hBY3RvcihTdHJpbmcoYm9keS5uYW1lIHx8ICIiKSk7CiAgICAgIGNvbnN0IGlucHV0ID0gYm9keS5pbnB1dDsKICAgICAgaWYgKCFpbnB1dCB8fCB0eXBlb2YgaW5wdXQgIT09ICJvYmplY3QiIHx8IEFycmF5LmlzQXJyYXkoaW5wdXQpKSB0aHJvdyBuZXcgQXBpZnlFcnJvcigiSW5wdXQgbXVzdCBiZSBhIEpTT04gb2JqZWN0LCBsaWtlIHtcImtleVwiOiBcInZhbHVlXCJ9LiIpOwogICAgICBjb25zdCBmaWVsZHMgPSBmb3JtRmllbGRzKGEuc2NoZW1hLCBleGFtcGxlT2YoYSkpOwogICAgICBjb25zdCBtaXNzaW5nID0gbWlzc2luZ1JlcXVpcmVkKGlucHV0LCBmaWVsZHMpOwogICAgICBpZiAobWlzc2luZy5sZW5ndGgpIHRocm93IG5ldyBBcGlmeUVycm9yKGBGaWxsIGluIHRoZSByZXF1aXJlZCBpbnB1dDogJHttaXNzaW5nLmpvaW4oIiwgIil9LmApOwogICAgICBjb25zdCBtYXhJdGVtcyA9IE1hdGgucm91bmQoY2xhbXBOdW0oYm9keS5tYXhJdGVtcywgMSwgTUFYX0lURU1TLCBERUZBVUxUX0xJTUlUKSk7CiAgICAgIGNvbnN0IG1heFRvdGFsQ2hhcmdlVXNkID0gY2xhbXBOdW0oYm9keS5tYXhVc2QsIDAuMDEsIE1BWF9VU0QsIDEpOwogICAgICBjb25zdCBydW4gPSBhd2FpdCBzdGFydFJ1bihhLm5hbWUsIGNsZWFuSW5wdXQoaW5wdXQsIGZpZWxkcyksIFRPS0VOLCB7IG1heEl0ZW1zLCBtYXhUb3RhbENoYXJnZVVzZCB9KTsKICAgICAgcmV0dXJuIGpzb24ocnVuKTsKICAgIH0KICAgIGlmIChwID09PSAiL2FwaS9ydW4iKSB7CiAgICAgIG5lZWRUb2tlbigpOwogICAgICBjb25zdCBpZCA9IHVybC5zZWFyY2hQYXJhbXMuZ2V0KCJpZCIpIHx8ICIiOwogICAgICBpZiAoIUlEX1JFLnRlc3QoaWQpKSB0aHJvdyBuZXcgQXBpZnlFcnJvcigiQmFkIHJ1biBpZC4iKTsKICAgICAgcmV0dXJuIGpzb24oYXdhaXQgZ2V0UnVuKGlkLCBUT0tFTiwgNSkpOwogICAgfQogICAgaWYgKHAgPT09ICIvYXBpL2Fib3J0IiAmJiByZXEubWV0aG9kID09PSAiUE9TVCIpIHsKICAgICAgbmVlZFRva2VuKCk7CiAgICAgIGNvbnN0IGlkID0gdXJsLnNlYXJjaFBhcmFtcy5nZXQoImlkIikgfHwgIiI7CiAgICAgIGlmICghSURfUkUudGVzdChpZCkpIHRocm93IG5ldyBBcGlmeUVycm9yKCJCYWQgcnVuIGlkLiIpOwogICAgICBhd2FpdCBhYm9ydFJ1bihpZCwgVE9LRU4pOwogICAgICByZXR1cm4ganNvbihhd2FpdCBnZXRSdW4oaWQsIFRPS0VOLCAzKSk7CiAgICB9CiAgICBpZiAocCA9PT0gIi9hcGkvbGFzdCIpIHsKICAgICAgbmVlZFRva2VuKCk7CiAgICAgIGNvbnN0IGEgPSBhd2FpdCBmZXRjaEFjdG9yKHVybC5zZWFyY2hQYXJhbXMuZ2V0KCJuYW1lIikgfHwgIiIpOwogICAgICByZXR1cm4ganNvbihhd2FpdCBsYXN0UnVuKGEubmFtZSwgVE9LRU4pKTsKICAgIH0KICAgIGlmIChwID09PSAiL2FwaS9pdGVtcyIpIHsKICAgICAgbmVlZFRva2VuKCk7CiAgICAgIGNvbnN0IGRzID0gdXJsLnNlYXJjaFBhcmFtcy5nZXQoImRhdGFzZXQiKSB8fCAiIjsKICAgICAgaWYgKCFJRF9SRS50ZXN0KGRzKSkgdGhyb3cgbmV3IEFwaWZ5RXJyb3IoIkJhZCBkYXRhc2V0IGlkLiIpOwogICAgICBjb25zdCBmb3JtYXQgPSB1cmwuc2VhcmNoUGFyYW1zLmdldCgiZm9ybWF0IikgfHwgImpzb24iOwogICAgICBjb25zdCBsaW1pdCA9IE1hdGgucm91bmQoY2xhbXBOdW0odXJsLnNlYXJjaFBhcmFtcy5nZXQoImxpbWl0IiksIDEsIE1BWF9JVEVNUywgTUFYX0lURU1TKSk7CiAgICAgIGNvbnN0IG5hbWUgPSAodXJsLnNlYXJjaFBhcmFtcy5nZXQoIm5hbWUiKSB8fCAicmVzdWx0cyIpLnJlcGxhY2UoL1teYS16MC05LV0vZ2ksICIiKS5zbGljZSgwLCA2MCkgfHwgInJlc3VsdHMiOwogICAgICBjb25zdCBpdGVtcyA9IGF3YWl0IGRhdGFzZXRJdGVtcyhkcywgVE9LRU4sIGxpbWl0KTsKICAgICAgaWYgKGZvcm1hdCA9PT0gInByZXZpZXciKSB7CiAgICAgICAgY29uc3Qgcm93cyA9IGl0ZW1zLm1hcChmbGF0dGVuSXRlbSk7CiAgICAgICAgY29uc3QgY29scyA9IHBsYW5Db2x1bW5zKHJvd3MpOwogICAgICAgIHJldHVybiBqc29uKHsgY29scywgcm93czogcm93cy5tYXAociA9PiBjb2xzLm1hcChjID0+IHJbY10gPz8gbnVsbCkpIH0pOwogICAgICB9CiAgICAgIGlmIChmb3JtYXQgPT09ICJjc3YiKSB7CiAgICAgICAgY29uc3Qgcm93cyA9IGl0ZW1zLm1hcChmbGF0dGVuSXRlbSk7CiAgICAgICAgcmV0dXJuIG5ldyBSZXNwb25zZSh0b0Nzdihyb3dzLCBwbGFuQ29sdW1ucyhyb3dzKSksIHsKICAgICAgICAgIGhlYWRlcnM6IHsgLi4uU0VDVVJJVFlfSEVBREVSUywgIkNvbnRlbnQtVHlwZSI6ICJ0ZXh0L2NzdjsgY2hhcnNldD11dGYtOCIsICJDb250ZW50LURpc3Bvc2l0aW9uIjogYGF0dGFjaG1lbnQ7IGZpbGVuYW1lPSIke2ZpbGVOYW1lKG5hbWUsICJjc3YiKX0iYCB9LAogICAgICAgIH0pOwogICAgICB9CiAgICAgIHJldHVybiBuZXcgUmVzcG9uc2UoSlNPTi5zdHJpbmdpZnkoaXRlbXMsIG51bGwsIDIpLCB7CiAgICAgICAgaGVhZGVyczogeyAuLi5TRUNVUklUWV9IRUFERVJTLCAiQ29udGVudC1UeXBlIjogImFwcGxpY2F0aW9uL2pzb247IGNoYXJzZXQ9dXRmLTgiLCAiQ29udGVudC1EaXNwb3NpdGlvbiI6IGBhdHRhY2htZW50OyBmaWxlbmFtZT0iJHtmaWxlTmFtZShuYW1lLCAianNvbiIpfSJgIH0sCiAgICAgIH0pOwogICAgfQogICAgcmV0dXJuIGpzb24oeyBlcnJvcjogIk5vdCBmb3VuZCIgfSwgNDA0KTsKICB9IGNhdGNoIChlKSB7CiAgICByZXR1cm4gZmFpbChlKTsKICB9Cn0KCmNvbnN0IFBBR0UgPSBgPCFkb2N0eXBlIGh0bWw+CjxodG1sIGxhbmc9ImVuIj48aGVhZD48bWV0YSBjaGFyc2V0PSJ1dGYtOCI+PG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCxpbml0aWFsLXNjYWxlPTEiPgo8dGl0bGU+QXBpZnkgU2NyYXBlciBSdW5uZXI8L3RpdGxlPgo8c3R5bGU+Cjpyb290ey0tYmc6I2Y3ZjdmODstLWNhcmQ6I2ZmZjstLWluazojMTYxNjFhOy0tbXV0ZTojNWQ1ZDY2Oy0tbGluZTojZTJlMmU2Oy0tYWNjOiM1YjNkZjU7LS1hY2MyOiNlZGU5ZmY7LS1iYWQ6I2I0MjMxODstLW9rOiMwNjc2NDd9CkBtZWRpYSAocHJlZmVycy1jb2xvci1zY2hlbWU6ZGFyayl7OnJvb3R7LS1iZzojMTIxMjE0Oy0tY2FyZDojMWMxYzIwOy0taW5rOiNlY2VjZjE7LS1tdXRlOiNhMGEwYWE7LS1saW5lOiMyZTJlMzQ7LS1hY2M6IzlkOGJmZjstLWFjYzI6IzJhMjQ0MjstLWJhZDojZmY4YTgwOy0tb2s6IzdlZTJhOH19Cip7Ym94LXNpemluZzpib3JkZXItYm94fVtoaWRkZW5de2Rpc3BsYXk6bm9uZSFpbXBvcnRhbnR9Ym9keXttYXJnaW46MDtiYWNrZ3JvdW5kOnZhcigtLWJnKTtjb2xvcjp2YXIoLS1pbmspO2ZvbnQ6MTVweC8xLjUgc3lzdGVtLXVpLC1hcHBsZS1zeXN0ZW0sU2Vnb2UgVUksUm9ib3RvLHNhbnMtc2VyaWZ9Cm1haW57bWF4LXdpZHRoOjExMDBweDttYXJnaW46MCBhdXRvO3BhZGRpbmc6MjBweCAxNnB4IDYwcHh9aDF7Zm9udC1zaXplOjIycHg7bWFyZ2luOjAgMCA0cHh9aDJ7Zm9udC1zaXplOjE2cHg7bWFyZ2luOjAgMCAxMHB4fQouc3Vie2NvbG9yOnZhcigtLW11dGUpO21hcmdpbjowIDAgMThweH0uY2FyZHtiYWNrZ3JvdW5kOnZhcigtLWNhcmQpO2JvcmRlcjoxcHggc29saWQgdmFyKC0tbGluZSk7Ym9yZGVyLXJhZGl1czoxMnB4O3BhZGRpbmc6MTZweDttYXJnaW4tYm90dG9tOjE0cHh9Ci5ncmlke2Rpc3BsYXk6Z3JpZDtncmlkLXRlbXBsYXRlLWNvbHVtbnM6MzQwcHggMWZyO2dhcDoxNHB4fUBtZWRpYShtYXgtd2lkdGg6ODAwcHgpey5ncmlke2dyaWQtdGVtcGxhdGUtY29sdW1uczoxZnJ9fS5ncmlkPnNlY3Rpb257bWluLXdpZHRoOjB9CmlucHV0LHRleHRhcmVhLGJ1dHRvbntmb250OmluaGVyaXQ7Y29sb3I6aW5oZXJpdH1pbnB1dFt0eXBlPXRleHRdLGlucHV0W3R5cGU9bnVtYmVyXSx0ZXh0YXJlYXt3aWR0aDoxMDAlO3BhZGRpbmc6OHB4IDEwcHg7Ym9yZGVyOjFweCBzb2xpZCB2YXIoLS1saW5lKTtib3JkZXItcmFkaXVzOjhweDtiYWNrZ3JvdW5kOnZhcigtLWJnKX0KdGV4dGFyZWF7Zm9udDoxM3B4LzEuNDUgdWktbW9ub3NwYWNlLE1lbmxvLG1vbm9zcGFjZTttaW4taGVpZ2h0OjIyMHB4O3Jlc2l6ZTp2ZXJ0aWNhbH0KYnV0dG9ue2JvcmRlcjowO2JvcmRlci1yYWRpdXM6OHB4O3BhZGRpbmc6OXB4IDE0cHg7YmFja2dyb3VuZDp2YXIoLS1hY2MpO2NvbG9yOiNmZmY7Y3Vyc29yOnBvaW50ZXI7Zm9udC13ZWlnaHQ6NjAwfWJ1dHRvbi5naG9zdHtiYWNrZ3JvdW5kOnZhcigtLWFjYzIpO2NvbG9yOnZhcigtLWluayl9YnV0dG9uOmRpc2FibGVke29wYWNpdHk6LjU7Y3Vyc29yOmRlZmF1bHR9CiNsaXN0e21heC1oZWlnaHQ6NTYwcHg7b3ZlcmZsb3c6YXV0bzttYXJnaW4tdG9wOjEwcHh9Lml0ZW17cGFkZGluZzo4cHggMTBweDtib3JkZXItcmFkaXVzOjhweDtjdXJzb3I6cG9pbnRlcjtib3JkZXI6MXB4IHNvbGlkIHRyYW5zcGFyZW50fS5pdGVtOmhvdmVye2JhY2tncm91bmQ6dmFyKC0tYWNjMil9Lml0ZW0ub257Ym9yZGVyLWNvbG9yOnZhcigtLWFjYyk7YmFja2dyb3VuZDp2YXIoLS1hY2MyKX0KLml0ZW0gYntkaXNwbGF5OmJsb2NrO2ZvbnQtc2l6ZToxNHB4fS5pdGVtIHNtYWxse2NvbG9yOnZhcigtLW11dGUpfS50YWd7ZGlzcGxheTppbmxpbmUtYmxvY2s7Zm9udC1zaXplOjExcHg7cGFkZGluZzoxcHggNnB4O2JvcmRlci1yYWRpdXM6OTlweDtiYWNrZ3JvdW5kOnZhcigtLWFjYzIpO2NvbG9yOnZhcigtLWFjYyk7bWFyZ2luLWxlZnQ6NnB4fQoucm93e2Rpc3BsYXk6ZmxleDtnYXA6MTBweDtmbGV4LXdyYXA6d3JhcDthbGlnbi1pdGVtczplbmR9LnJvdyBsYWJlbHtmbGV4OjE7bWluLXdpZHRoOjE0MHB4O2ZvbnQtc2l6ZToxM3B4O2NvbG9yOnZhcigtLW11dGUpfQoubXNne3BhZGRpbmc6MTBweCAxMnB4O2JvcmRlci1yYWRpdXM6OHB4O2JhY2tncm91bmQ6dmFyKC0tYWNjMik7bWFyZ2luOjEwcHggMH0ubXNnLmJhZHtjb2xvcjp2YXIoLS1iYWQpfS5tc2cub2t7Y29sb3I6dmFyKC0tb2spfQoudGFibGV3cmFwe292ZXJmbG93OmF1dG87bWF4LWhlaWdodDo0MjBweDtib3JkZXI6MXB4IHNvbGlkIHZhcigtLWxpbmUpO2JvcmRlci1yYWRpdXM6OHB4fXRhYmxle2JvcmRlci1jb2xsYXBzZTpjb2xsYXBzZTtmb250LXNpemU6MTJweDttaW4td2lkdGg6MTAwJX10aCx0ZHtwYWRkaW5nOjVweCA4cHg7Ym9yZGVyLWJvdHRvbToxcHggc29saWQgdmFyKC0tbGluZSk7dGV4dC1hbGlnbjpsZWZ0O3ZlcnRpY2FsLWFsaWduOnRvcDttYXgtd2lkdGg6MzIwcHg7b3ZlcmZsb3c6aGlkZGVuO3RleHQtb3ZlcmZsb3c6ZWxsaXBzaXM7d2hpdGUtc3BhY2U6bm93cmFwfXRoe3Bvc2l0aW9uOnN0aWNreTt0b3A6MDtiYWNrZ3JvdW5kOnZhcigtLWNhcmQpfQpkZXRhaWxze21hcmdpbi10b3A6MTBweDtmb250LXNpemU6MTNweDtjb2xvcjp2YXIoLS1tdXRlKX1kZXRhaWxzIGxpe21hcmdpbjo0cHggMH1he2NvbG9yOnZhcigtLWFjYyl9Zm9vdGVye2NvbG9yOnZhcigtLW11dGUpO2ZvbnQtc2l6ZToxM3B4O21hcmdpbi10b3A6MjRweH0Kb2x7bWFyZ2luOjZweCAwIDAgMThweDtwYWRkaW5nOjB9Cjwvc3R5bGU+PC9oZWFkPjxib2R5PjxtYWluPgo8aDE+QXBpZnkgU2NyYXBlciBSdW5uZXI8L2gxPgo8cCBjbGFzcz0ic3ViIj5SdW4gYW55IG9mIDE5MCsgcmVhZHktbWFkZSBDbGlxdG8gTWVkaWEgd2ViIHNjcmFwZXJzIG9uIEFwaWZ5IGFuZCBkb3dubG9hZCB0aGUgcmVzdWx0cyBhcyBDU1Ygb3IgSlNPTi4gUnVucyB1c2UgeW91ciBvd24gQXBpZnkgYWNjb3VudCBhbmQgdG9rZW4uPC9wPgo8ZGl2IGlkPSJzZXR1cCI+PC9kaXY+CjxkaXYgY2xhc3M9ImdyaWQiPgo8c2VjdGlvbiBjbGFzcz0iY2FyZCI+PGgyPjEuIFBpY2sgYSBzY3JhcGVyPC9oMj48aW5wdXQgaWQ9InEiIHR5cGU9InRleHQiIHBsYWNlaG9sZGVyPSJTZWFyY2g6IHJlZGRpdCwgeW91dHViZSwgZ29vZ2xlIG1hcHMsIHJldmlld3PigJrDhMK2Ij48ZGl2IGlkPSJjb3VudCIgY2xhc3M9InN1YiIgc3R5bGU9Im1hcmdpbjo2cHggMCAwIj5Mb2FkaW5nIHRoZSBzY3JhcGVyIGxpc3RcdTIwMjY8L2Rpdj48ZGl2IGlkPSJsaXN0Ij48L2Rpdj48L3NlY3Rpb24+CjxzZWN0aW9uPgo8ZGl2IGNsYXNzPSJjYXJkIiBpZD0iYWN0b3JDYXJkIj48aDI+Mi4gU2V0IHRoZSBpbnB1dDwvaDI+PHAgY2xhc3M9InN1YiIgaWQ9ImhpbnQiPkNob29zZSBhIHNjcmFwZXIgb24gdGhlIGxlZnQuIEl0cyBpbnB1dCBvcGVucyBoZXJlIHdpdGggYSB3b3JraW5nIGV4YW1wbGUuPC9wPjwvZGl2Pgo8ZGl2IGNsYXNzPSJjYXJkIiBpZD0icmVzdWx0Q2FyZCIgaGlkZGVuPjxoMj4zLiBSZXN1bHRzPC9oMj48ZGl2IGlkPSJzdGF0dXMiPjwvZGl2PjxkaXYgY2xhc3M9InJvdyIgaWQ9ImRsIiBoaWRkZW4+PGJ1dHRvbiBjbGFzcz0iZ2hvc3QiIGlkPSJjc3YiPkRvd25sb2FkIENTVjwvYnV0dG9uPjxidXR0b24gY2xhc3M9Imdob3N0IiBpZD0ianNvbmIiPkRvd25sb2FkIEpTT048L2J1dHRvbj48L2Rpdj48ZGl2IGNsYXNzPSJ0YWJsZXdyYXAiIGlkPSJ0dyIgaGlkZGVuPjwvZGl2PjwvZGl2Pgo8L3NlY3Rpb24+PC9kaXY+Cjxmb290ZXI+TWFkZSBieSA8YSBpZD0ic2l0ZSIgaHJlZj0iaHR0cHM6Ly9jbGlxdG9tZWRpYS5jb20vYWN0b3JzLyIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIiPkNsaXF0byBNZWRpYTwvYT4uIEFwaWZ5IGNoYXJnZXMgb25seSBmb3IgeW91ciBvd24gcnVucy4gWW91ciB0b2tlbiBzdGF5cyBpbiB5b3VyIFJhaWx3YXkgVmFyaWFibGVzIGFuZCBpcyBuZXZlciBzZW50IHRvIHRoaXMgcGFnZS48L2Zvb3Rlcj4KPC9tYWluPgo8c2NyaXB0Pgpjb25zdCAkPXM9PmRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Iocyk7bGV0IEFDVD1udWxsLFJVTj1udWxsLFBPTEw9bnVsbCxTVEFUVVM9e307CmNvbnN0IGVzYz1zPT5TdHJpbmcocz8/JycpLnJlcGxhY2UoL1smPD4iJ10vZyxjPT4oeycmJzonJmFtcDsnLCc8JzonJmx0OycsJz4nOicmZ3Q7JywnIic6JyZxdW90OycsIiciOicmIzM5Oyd9W2NdKSk7CmNvbnN0IE89bG9jYXRpb24ub3JpZ2luO2FzeW5jIGZ1bmN0aW9uIGFwaShwYXRoLG9wdCl7Y29uc3Qgcj1hd2FpdCBmZXRjaChPK3BhdGgsb3B0KTtjb25zdCB0PWF3YWl0IHIudGV4dCgpO2xldCBqPW51bGw7dHJ5e2o9SlNPTi5wYXJzZSh0KX1jYXRjaHt9aWYoIXIub2spdGhyb3cgT2JqZWN0LmFzc2lnbihuZXcgRXJyb3IoKGomJmouZXJyb3IpfHwoJ0Vycm9yICcrci5zdGF0dXMpKSx7dXJsOmomJmoudXJsfSk7cmV0dXJuIGp9CmZ1bmN0aW9uIHVzZChuKXtpZihuPT1udWxsKXJldHVybicnO2lmKG49PT0wKXJldHVybickMCc7aWYobjwwLjAxKXJldHVybickJytuLnRvRml4ZWQoNCkucmVwbGFjZSgvMCskLywnJyk7cmV0dXJuJyQnK24udG9GaXhlZCgyKX0KYXN5bmMgZnVuY3Rpb24gc3RhdHVzKCl7U1RBVFVTPWF3YWl0IGFwaSgnL2FwaS9zdGF0dXMnKTskKCcjc2l0ZScpLmhyZWY9U1RBVFVTLnNpdGU7bGV0IGg9Jyc7CmlmKCFTVEFUVVMudG9rZW5TZXQpaD0nPGRpdiBjbGFzcz0ibXNnIGJhZCI+PGI+QWRkIHlvdXIgQXBpZnkgdG9rZW4gdG8gc3RhcnQuPC9iPjxvbD48bGk+U2lnbiB1cCBmb3IgZnJlZSBhdCA8YSBocmVmPSJodHRwczovL2NvbnNvbGUuYXBpZnkuY29tL3NpZ24tdXAiIHRhcmdldD0iX2JsYW5rIiByZWw9Im5vb3BlbmVyIj5hcGlmeS5jb208L2E+ICh0aGUgZnJlZSBwbGFuIGluY2x1ZGVzIG1vbnRobHkgY3JlZGl0KS48L2xpPjxsaT5PcGVuIEFwaWZ5IENvbnNvbGUg4oCaw5zDrSBTZXR0aW5ncyDigJrDnMOtIDxhIGhyZWY9Imh0dHBzOi8vY29uc29sZS5hcGlmeS5jb20vc2V0dGluZ3MvaW50ZWdyYXRpb25zIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub29wZW5lciI+QVBJICZhbXA7IEludGVncmF0aW9uczwvYT4gYW5kIGNvcHkgeW91ciBQZXJzb25hbCBBUEkgdG9rZW4uPC9saT48bGk+SW4gUmFpbHdheSwgb3BlbiB0aGlzIHNlcnZpY2Ug4oCaw5zDrSBWYXJpYWJsZXMsIHBhc3RlIGl0IGludG8gPGI+QVBJRllfVE9LRU48L2I+IGFuZCBwcmVzcyBEZXBsb3kuPC9saT48L29sPllvdSBjYW4gYnJvd3NlIHNjcmFwZXJzIGFuZCBpbnB1dHMgYmVsb3cgbWVhbndoaWxlLjwvZGl2Pic7CmVsc2UgaWYoU1RBVFVTLmVycm9yKWg9JzxkaXYgY2xhc3M9Im1zZyBiYWQiPicrZXNjKFNUQVRVUy5lcnJvcikrJzwvZGl2Pic7CmVsc2UgaD0nPGRpdiBjbGFzcz0ibXNnIG9rIj5Db25uZWN0ZWQgdG8gQXBpZnkgYXMgPGI+Jytlc2MoU1RBVFVTLmFjY291bnQpKyc8L2I+LiBSdW5zIGFyZSBiaWxsZWQgdG8gdGhpcyBhY2NvdW50LjwvZGl2Pic7CmlmKCFTVEFUVVMucGFzc3dvcmRTZXQpaCs9JzxkaXYgY2xhc3M9Im1zZyBiYWQiPkFDQ0VTU19QQVNTV09SRCBpcyBlbXB0eS4gU2V0IGl0IGluIFJhaWx3YXkg4oCaw5zDrSBWYXJpYWJsZXMgc28gbm9ib2R5IGVsc2UgY2FuIHVzZSB5b3VyIGNyZWRpdC4gUnVucyBhcmUgb2ZmIHVudGlsIHRoZW4uPC9kaXY+JzsKJCgnI3NldHVwJykuaW5uZXJIVE1MPWh9CmxldCBMSVNUPVtdLFQ9bnVsbDsKYXN5bmMgZnVuY3Rpb24gbG9hZChxKXtjb25zdCBkPWF3YWl0IGFwaSgnL2FwaS9hY3RvcnM/cT0nK2VuY29kZVVSSUNvbXBvbmVudChxfHwnJykpO0xJU1Q9ZC5pdGVtczskKCcjY291bnQnKS50ZXh0Q29udGVudD1kLnRvdGFsKycgc2NyYXBlcnMnOwokKCcjbGlzdCcpLmlubmVySFRNTD1MSVNULm1hcCgoYSxpKT0+JzxkaXYgY2xhc3M9Iml0ZW0nKyhBQ1QmJkFDVC5uYW1lPT09YS5uYW1lPycgb24nOicnKSsnIiBkYXRhLWk9IicraSsnIj48Yj4nK2VzYyhhLnRpdGxlKSsoYS50ZXN0ZWQ/JzxzcGFuIGNsYXNzPSJ0YWciPnRlc3RlZCBleGFtcGxlPC9zcGFuPic6JycpKyc8L2I+PHNtYWxsPicrKGEucHJpY2UhPW51bGw/dXNkKGEucHJpY2UpKycgLyAnK2VzYyhhLnVuaXQpKycgwqziiJEgJzonJykrYS51c2VycysnIHVzZXJzPC9zbWFsbD48L2Rpdj4nKS5qb2luKCcnKXx8JzxwIGNsYXNzPSJzdWIiPk5vdGhpbmcgZm91bmQuIFRyeSBhbm90aGVyIHdvcmQuPC9wPid9CiQoJyNsaXN0Jykub25jbGljaz1lPT57Y29uc3QgZWw9ZS50YXJnZXQuY2xvc2VzdCgnLml0ZW0nKTtpZihlbClwaWNrKExJU1RbK2VsLmRhdGFzZXQuaV0ubmFtZSl9OwokKCcjcScpLm9uaW5wdXQ9KCk9PntjbGVhclRpbWVvdXQoVCk7VD1zZXRUaW1lb3V0KCgpPT5sb2FkKCQoJyNxJykudmFsdWUpLmNhdGNoKGVyciksMjUwKX07CmZ1bmN0aW9uIGVycihlKXskKCcjc3RhdHVzJykuaW5uZXJIVE1MPSc8ZGl2IGNsYXNzPSJtc2cgYmFkIj4nK2VzYyhlLm1lc3NhZ2UpKyhlLnVybD8nIDxhIGhyZWY9IicrZXNjKGUudXJsKSsnIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub29wZW5lciI+T3BlbiB0aGUgcnVuIGluIEFwaWZ5PC9hPic6JycpKyc8L2Rpdj4nOyQoJyNyZXN1bHRDYXJkJykuaGlkZGVuPWZhbHNlfQphc3luYyBmdW5jdGlvbiBwaWNrKG5hbWUpeyQoJyNhY3RvckNhcmQnKS5pbm5lckhUTUw9JzxoMj4yLiBTZXQgdGhlIGlucHV0PC9oMj48cCBjbGFzcz0ic3ViIj5Mb2FkaW5n4oCaw4TCtjwvcD4nOwp0cnl7QUNUPWF3YWl0IGFwaSgnL2FwaS9hY3Rvcj9uYW1lPScrZW5jb2RlVVJJQ29tcG9uZW50KG5hbWUpKX1jYXRjaChlKXskKCcjYWN0b3JDYXJkJykuaW5uZXJIVE1MPSc8aDI+Mi4gU2V0IHRoZSBpbnB1dDwvaDI+PGRpdiBjbGFzcz0ibXNnIGJhZCI+Jytlc2MoZS5tZXNzYWdlKSsnPC9kaXY+JztyZXR1cm59CmRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5pdGVtJykuZm9yRWFjaChlbD0+ZWwuY2xhc3NMaXN0LnRvZ2dsZSgnb24nLExJU1RbK2VsLmRhdGFzZXQuaV0mJkxJU1RbK2VsLmRhdGFzZXQuaV0ubmFtZT09PW5hbWUpKTsKY29uc3QgZj1BQ1QuZmllbGRzLm1hcCh4PT4nPGxpPjxjb2RlPicrZXNjKHgua2V5KSsnPC9jb2RlPicrKHgucmVxdWlyZWQ/JyA8Yj4ocmVxdWlyZWQpPC9iPic6JycpKycg4oCaw4TDriAnK2VzYyh4LmxhYmVsKSsoeC5oZWxwPyc6ICcrZXNjKHguaGVscCk6JycpKyh4Lm9wdGlvbnMubGVuZ3RoPycgT3B0aW9uczogJytlc2MoeC5vcHRpb25zLmpvaW4oJywgJykpOicnKSsnPC9saT4nKS5qb2luKCcnKTsKJCgnI2FjdG9yQ2FyZCcpLmlubmVySFRNTD0nPGgyPjIuICcrZXNjKEFDVC50aXRsZSkrJzwvaDI+PHAgY2xhc3M9InN1YiI+Jytlc2MoQUNULmRlc2NyaXB0aW9uKSsnIDxhIGhyZWY9IicrZXNjKEFDVC5zaXRlKSsnIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub29wZW5lciI+QWJvdXQgdGhpcyBzY3JhcGVyPC9hPjwvcD4nKwonPGxhYmVsIGNsYXNzPSJzdWIiPklucHV0IChKU09OKSwgcHJlZmlsbGVkIHdpdGggJytlc2MoQUNULnNvdXJjZSkrJzwvbGFiZWw+PHRleHRhcmVhIGlkPSJpbnB1dCIgc3BlbGxjaGVjaz0iZmFsc2UiPicrZXNjKEpTT04uc3RyaW5naWZ5KEFDVC5pbnB1dCxudWxsLDIpKSsnPC90ZXh0YXJlYT4nKwooZj8nPGRldGFpbHM+PHN1bW1hcnk+QWxsIGlucHV0IGZpZWxkczwvc3VtbWFyeT48dWw+JytmKyc8L3VsPjwvZGV0YWlscz4nOicnKSsKJzxkaXYgY2xhc3M9InJvdyIgc3R5bGU9Im1hcmdpbi10b3A6MTJweCI+PGxhYmVsPk1heCByZXN1bHRzPGlucHV0IGlkPSJtaSIgdHlwZT0ibnVtYmVyIiBtaW49IjEiIG1heD0iJytTVEFUVVMubWF4SXRlbXMrJyIgdmFsdWU9IjIwIj48L2xhYmVsPjxsYWJlbD5Db3N0IGNhcCwgVVNEPGlucHV0IGlkPSJtdSIgdHlwZT0ibnVtYmVyIiBtaW49IjAuMDEiIG1heD0iJytTVEFUVVMubWF4VXNkKyciIHN0ZXA9IjAuMDEiIHZhbHVlPSIwLjUwIj48L2xhYmVsPicrCic8YnV0dG9uIGlkPSJnbyI+UnVuPC9idXR0b24+PGJ1dHRvbiBjbGFzcz0iZ2hvc3QiIGlkPSJzdG9wIiBoaWRkZW4+U3RvcDwvYnV0dG9uPjxidXR0b24gY2xhc3M9Imdob3N0IiBpZD0ibGFzdCI+TG9hZCBsYXN0IHJ1bjwvYnV0dG9uPjwvZGl2PjxwIGNsYXNzPSJzdWIiIGlkPSJlc3QiIHN0eWxlPSJtYXJnaW46OHB4IDAgMCI+Jytlc2MoQUNULmVzdGltYXRlKSsnIFRoZSBydW4gc3RvcHMgYXQgd2hpY2hldmVyIGNhcCBjb21lcyBmaXJzdC48L3A+JzsKJCgnI2dvJykub25jbGljaz1ydW47JCgnI3N0b3AnKS5vbmNsaWNrPXN0b3A7JCgnI2xhc3QnKS5vbmNsaWNrPWxhc3Q7JCgnI2dvJykuZGlzYWJsZWQ9IVNUQVRVUy50b2tlblNldHx8IVNUQVRVUy5wYXNzd29yZFNldH0KZnVuY3Rpb24gc2hvdyhyKXtSVU49cjtjb25zdCBkb25lPVsnU1VDQ0VFREVEJywnRkFJTEVEJywnQUJPUlRFRCcsJ1RJTUVELU9VVCddLmluY2x1ZGVzKHIuc3RhdHVzKTsKJCgnI3N0YXR1cycpLmlubmVySFRNTD0nPGRpdiBjbGFzcz0ibXNnJysoci5zdGF0dXM9PT0nU1VDQ0VFREVEJz8nIG9rJzpkb25lPycgYmFkJzonJykrJyI+U3RhdHVzOiA8Yj4nK2VzYyhyLnN0YXR1cykrJzwvYj4gwqziiJEgJytyLml0ZW1Db3VudCsnIHJlc3VsdHMnKyhyLnVzZCE9bnVsbD8nIMKs4oiRIGNvc3Qgc28gZmFyICcrdXNkKHIudXNkKTonJykrKHIuc3RhdHVzTWVzc2FnZT8nIMKs4oiRICcrZXNjKHIuc3RhdHVzTWVzc2FnZSk6JycpKycgwqziiJEgPGEgaHJlZj0iJytlc2Moci51cmwpKyciIHRhcmdldD0iX2JsYW5rIiByZWw9Im5vb3BlbmVyIj5PcGVuIGluIEFwaWZ5PC9hPjwvZGl2Pic7CiQoJyNyZXN1bHRDYXJkJykuaGlkZGVuPWZhbHNlOyQoJyNzdG9wJykuaGlkZGVuPWRvbmU7JCgnI2dvJykuZGlzYWJsZWQ9IWRvbmU7cmV0dXJuIGRvbmV9CmFzeW5jIGZ1bmN0aW9uIHJ1bigpe2xldCBpbnB1dDt0cnl7aW5wdXQ9SlNPTi5wYXJzZSgkKCcjaW5wdXQnKS52YWx1ZSl9Y2F0Y2h7cmV0dXJuIGVycihuZXcgRXJyb3IoJ1RoZSBpbnB1dCBpcyBub3QgdmFsaWQgSlNPTi4gQ2hlY2sgY29tbWFzIGFuZCBxdW90ZXMuJykpfQokKCcjZ28nKS5kaXNhYmxlZD10cnVlOyQoJyNkbCcpLmhpZGRlbj10cnVlOyQoJyN0dycpLmhpZGRlbj10cnVlOwp0cnl7Y29uc3Qgcj1hd2FpdCBhcGkoJy9hcGkvcnVuJyx7bWV0aG9kOidQT1NUJyxoZWFkZXJzOnsnQ29udGVudC1UeXBlJzonYXBwbGljYXRpb24vanNvbid9LGJvZHk6SlNPTi5zdHJpbmdpZnkoe25hbWU6QUNULm5hbWUsaW5wdXQsbWF4SXRlbXM6KyQoJyNtaScpLnZhbHVlLG1heFVzZDorJCgnI211JykudmFsdWV9KX0pO3Nob3cocik7cG9sbCgpfWNhdGNoKGUpeyQoJyNnbycpLmRpc2FibGVkPWZhbHNlO2VycihlKX19CmxldCBTRVRUTEU9MDthc3luYyBmdW5jdGlvbiBwb2xsKCl7Y2xlYXJUaW1lb3V0KFBPTEwpO3RyeXtjb25zdCByPWF3YWl0IGFwaSgnL2FwaS9ydW4/aWQ9JytSVU4uaWQpO2lmKHNob3cocikpe2lmKCFyLml0ZW1Db3VudCYmU0VUVExFKys8NCl7UE9MTD1zZXRUaW1lb3V0KHBvbGwsMjAwMCk7cmV0dXJufVNFVFRMRT0wO3JldHVybiByZXN1bHRzKCl9fWNhdGNoKGUpe2VycihlKX1QT0xMPXNldFRpbWVvdXQocG9sbCwxNTAwKX0KYXN5bmMgZnVuY3Rpb24gc3RvcCgpe3RyeXtzaG93KGF3YWl0IGFwaSgnL2FwaS9hYm9ydD9pZD0nK1JVTi5pZCx7bWV0aG9kOidQT1NUJ30pKTtyZXN1bHRzKCl9Y2F0Y2goZSl7ZXJyKGUpfX0KYXN5bmMgZnVuY3Rpb24gbGFzdCgpe3RyeXtzaG93KGF3YWl0IGFwaSgnL2FwaS9sYXN0P25hbWU9JytlbmNvZGVVUklDb21wb25lbnQoQUNULm5hbWUpKSk7cmVzdWx0cygpfWNhdGNoKGUpe2VycihlKX19CmFzeW5jIGZ1bmN0aW9uIHJlc3VsdHMoKXtpZighUlVOfHwhUlVOLml0ZW1Db3VudClyZXR1cm47Y29uc3QgZD1hd2FpdCBhcGkoJy9hcGkvaXRlbXM/Zm9ybWF0PXByZXZpZXcmbGltaXQ9NTAmZGF0YXNldD0nK1JVTi5kYXRhc2V0SWQpOwokKCcjdHcnKS5pbm5lckhUTUw9Jzx0YWJsZT48dHI+JytkLmNvbHMubWFwKGM9Pic8dGg+Jytlc2MoYykrJzwvdGg+Jykuam9pbignJykrJzwvdHI+JytkLnJvd3MubWFwKHI9Pic8dHI+JytyLm1hcCh2PT4nPHRkIHRpdGxlPSInK2VzYyh2KSsnIj4nK2VzYyh2KSsnPC90ZD4nKS5qb2luKCcnKSsnPC90cj4nKS5qb2luKCcnKSsnPC90YWJsZT4nOwokKCcjdHcnKS5oaWRkZW49ZmFsc2U7JCgnI2RsJykuaGlkZGVuPWZhbHNlO2NvbnN0IGJhc2U9TysnL2FwaS9pdGVtcz9uYW1lPScrZW5jb2RlVVJJQ29tcG9uZW50KEFDVC5uYW1lKSsnJmRhdGFzZXQ9JytSVU4uZGF0YXNldElkKycmZm9ybWF0PSc7JCgnI2NzdicpLm9uY2xpY2s9KCk9PmxvY2F0aW9uLmhyZWY9YmFzZSsnY3N2JzskKCcjanNvbmInKS5vbmNsaWNrPSgpPT5sb2NhdGlvbi5ocmVmPWJhc2UrJ2pzb24nfQpzdGF0dXMoKS5jYXRjaChlPT4kKCcjc2V0dXAnKS5pbm5lckhUTUw9JzxkaXYgY2xhc3M9Im1zZyBiYWQiPicrZXNjKGUubWVzc2FnZSkrJzwvZGl2PicpO2xvYWQoJycpLmNhdGNoKGVycik7Cjwvc2NyaXB0PjwvYm9keT48L2h0bWw+YDsKCkJ1bi5zZXJ2ZSh7IHBvcnQ6IFBPUlQsIGhvc3RuYW1lOiAiMC4wLjAuMCIsIGZldGNoOiBoYW5kbGUgfSk7CmNvbnNvbGUubG9nKGBBcGlmeSBTY3JhcGVyIFJ1bm5lciBpcyBsaXN0ZW5pbmcgb24gcG9ydCAke1BPUlR9LiBUb2tlbiBzZXQ6ICR7VE9LRU4gPyAieWVzIiA6ICJubyJ9LiBQYXNzd29yZCBzZXQ6ICR7UEFTU1dPUkQgPyAieWVzIiA6ICJubyJ9LmApOwo=`
- **Health check:** /health
- **Public domain:** Yes

## Documentation

# Deploy and Host Apify Scraper Runner on Railway

Apify Scraper Runner is a small private web app that runs more than 190 ready-made Apify web scrapers by Cliqto Media: Reddit, YouTube transcripts, Google Trends, Google Play reviews, Trustpilot, Pinterest, Threads, website contacts and more. Pick a scraper, set limits, click Run, and download the results as CSV or JSON. No code needed.

## About Hosting Apify Scraper Runner

The template deploys one Bun service from a single TypeScript file. It needs two variables. `APIFY_TOKEN` is your own Apify API token (Apify Console, Settings, API &amp; Integrations); it stays on the server and is never sent to the browser. `ACCESS_PASSWORD` is generated for you and protects the page with a browser login (any user name plus this password). After the deploy, open the public URL, pick a scraper and run it. Every run has a `Max results` limit (1 to 10,000) and a `Cost cap` ($0.01 to $25), and Apify stops the run at the limit you set. The `/health` path is used as the healthcheck.

## Common Use Cases

- Collect Reddit posts, Trustpilot or Google Play reviews for market and product research
- Pull YouTube transcripts, Google Trends and autocomplete keywords for content and SEO work
- Find contact details on company websites and export them to CSV for a spreadsheet or CRM

## Dependencies for Apify Scraper Runner Hosting

- An Apify account and API token (free plan available at console.apify.com)
- Railway, which runs the Bun service (image `ghcr.io/railwayapp/function-bun`)

### Deployment Dependencies

- Scraper catalog with docs and examples: https://cliqtomedia.com/actors/?utm_source=railway&amp;utm_medium=template&amp;utm_campaign=promo-2026-11
- Apify API token docs: https://docs.apify.com/platform/integrations/api#api-token

### Implementation Details

Example input for `google-autocomplete-scraper`:

```json
{ "keywords": ["coffee"], "language": "en", "country": "us", "maxResults": 50 }
```

One row of the result:

```json
{ "suggestion": "coffee near me", "seed": "coffee", "language": "en", "country": "us" }
```

Pricing: the template is free. Railway bills you for hosting. Apify charges only for your own runs on your own account; each scraper's price is on its page. The app runs Cliqto Media scrapers (`cliqtomedia/...`) only. The preview shows 50 rows; CSV and JSON downloads include up to 10,000 rows.

## Why Deploy Apify Scraper Runner on Railway?


Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Apify Scraper Runner on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.



## Similar templates

- [N8N Main + Worker](https://railway.com/deploy/n8n-main-worker) — Deploy and Host N8N with Inactive worker.
- [Evolution API with n8n](https://railway.com/deploy/evolution-api-with-n8n) — Automate WhatsApp workflows with Evolution API, n8n, and Postgres.
- [Postgres Backup](https://railway.com/deploy/postgres-s3-backups) — Cron-based PostgreSQL backup to bucket storage

Open this page in a browser: https://railway.com/deploy/apify-scraper-runner
