From 3a27b7facf95d4bf78ea2d55e2cff262e5348ccd Mon Sep 17 00:00:00 2001 From: john zhang Date: Fri, 26 Feb 2016 13:35:14 -0800 Subject: [PATCH 01/14] epicenter-1590 update path of cookie base on acc/project --- dist/components/assignment/assignment.js | 2 +- src/managers/auth-manager.js | 44 +++++++++++++----------- src/store/cookie-store.js | 6 ++-- tests/spec/test-auth-manager.js | 10 +++++- 4 files changed, 36 insertions(+), 26 deletions(-) diff --git a/dist/components/assignment/assignment.js b/dist/components/assignment/assignment.js index 74ae582d..947e5bfa 100644 --- a/dist/components/assignment/assignment.js +++ b/dist/components/assignment/assignment.js @@ -1231,4 +1231,4 @@ module.exports = function (base, props, staticProps) { }; },{}]},{},[6]) -//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Fzc2lnbm1lbnQtcm93LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9hc3NpZ25tZW50LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9iYXNlLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Jhc2UtbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2RlZmF1bHRzLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9pbmRleC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvcHJvamVjdC1tb2RlbC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvc2VydmljZS1sb2NhdG9yLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy90ZW1wbGF0ZXMuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXItbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXJzLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3dvcmxkLW1vZGVsLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy93b3JsZHMtY29sbGVjdGlvbi5qcyIsInNyYy91dGlsL2FqYXgtcXVldWUuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCc7XG5cbnZhciB0ZW1wbGF0ZXMgPSByZXF1aXJlKCcuL3RlbXBsYXRlcycpO1xuXG52YXIgQXNzaWdubWVudFJvdyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy4kZWwgPSAkKCc8dHI+Jyk7XG4gICAgdGhpcy5lbCA9IHRoaXMuJGVsWzBdO1xuICAgIHRoaXMuJCA9IF8ucGFydGlhbFJpZ2h0KCQsIHRoaXMuJGVsKTtcblxuICAgIHRoaXMubW9kZWwgPSBvcHRpb25zLm1vZGVsO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy53b3JsZHMgPSBvcHRpb25zLndvcmxkcztcbiAgICB0aGlzLnByb2plY3QgPSBvcHRpb25zLnByb2plY3Q7XG5cbiAgICBfLmJpbmRBbGwodGhpcywgWydzZXRFZGl0TW9kZScsICdyZW1vdmVFZGl0TW9kZScsICdzYXZlRWRpdCcsICdjYW5jZWxFZGl0JywgJ3VwZGF0ZURhdGEnXSk7XG5cbiAgICB0aGlzLmJpbmRFdmVudHMoKTtcblxufTtcblxuXy5leHRlbmQoQXNzaWdubWVudFJvdy5wcm90b3R5cGUsIHtcblxuICAgIHRlbXBsYXRlOiB0ZW1wbGF0ZXNbJ3VzZXItcm93J10sXG5cbiAgICBlZGl0VGVtcGxhdGU6IHRlbXBsYXRlc1snZWRpdC11c2VyLXJvdyddLFxuXG4gICAgYmluZEV2ZW50czogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnYnV0dG9uLmVkaXQnLCB0aGlzLnNldEVkaXRNb2RlKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2J1dHRvbi5zYXZlJywgdGhpcy5zYXZlRWRpdCk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICdidXR0b24uY2FuY2VsJywgdGhpcy5jYW5jZWxFZGl0KTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9mZignY2xpY2snLCBudWxsLCBudWxsKTtcbiAgICAgICAgLy8gdGhpcyBvbmx5IGdpdmVzIGEgZGVsYXkgdG8gcmVtb3ZlIHRoZSB0clxuICAgICAgICAvLyBhbmltYXRpb24gb2YgaGVpZ2h0IG9mIHRoZSB0ciBkb2VzIG5vdCB3b3JrXG4gICAgICAgIHRoaXMuJCgnOmNoZWNrYm94JykuYXR0cignY2hlY2tlZCcsIGZhbHNlKTtcbiAgICAgICAgdGhpcy4kZWxcbiAgICAgICAgICAgIC5jc3MoeyBvcGFjaXR5OiAwLjMgfSlcbiAgICAgICAgICAgIC5hbmltYXRlKHsgaGVpZ2h0OiAwIH0sIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMzAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIG1ha2VJbmFjdGl2ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tb2RlbC5tYWtlSW5hY3RpdmUoKTtcbiAgICB9LFxuXG4gICAgc2V0RWRpdE1vZGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5tb2RlbC5zZXQoJ2VkaXQtbW9kZScsIHRydWUpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICByZW1vdmVFZGl0TW9kZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLm1vZGVsLnNldCgnZWRpdC1tb2RlJywgZmFsc2UpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICBzYXZlRWRpdDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB0aGlzLnVwZGF0ZURhdGEoKTtcbiAgICAgICAgdGhpcy53b3JsZHNcbiAgICAgICAgICAgIC51cGRhdGVVc2VyKHRoaXMubW9kZWwpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMucmVtb3ZlRWRpdE1vZGUoKTtcbiAgICAgICAgICAgICAgICBfdGhpcy4kZWwudHJpZ2dlcigndXBkYXRlJywgX3RoaXMpO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGNhbmNlbEVkaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVFZGl0TW9kZSgpO1xuICAgIH0sXG5cbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHRlbXBsID0gdGhpcy5tb2RlbC5nZXQoJ2VkaXQtbW9kZScpID8gdGhpcy5lZGl0VGVtcGxhdGUgOiB0aGlzLnRlbXBsYXRlO1xuICAgICAgICB2YXIgdm0gPSBfLmV4dGVuZCh7XG4gICAgICAgICAgICByb2xlczogdGhpcy5wcm9qZWN0LmdldCgncm9sZXMnKSxcbiAgICAgICAgICAgIG9wdGlvbmFsUm9sZXM6IHRoaXMucHJvamVjdC5nZXQoJ29wdGlvbmFsUm9sZXMnKSxcbiAgICAgICAgICAgIHdvcmxkczogdGhpcy53b3JsZHMuZ2V0V29ybGROYW1lcygpLFxuICAgICAgICAgICAgbmV3V29ybGQ6IHRoaXMud29ybGRzLmdldE5leHRXb3JsZE5hbWUoKVxuICAgICAgICB9LCB0aGlzLm1vZGVsLnRvSlNPTigpKTtcblxuICAgICAgICB0aGlzLiRlbC5odG1sKHRlbXBsKHZtKSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIHVwZGF0ZURhdGE6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdGhpcy4kKCdbZGF0YS1maWVsZF0nKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBlbCA9ICQodGhpcyk7XG4gICAgICAgICAgICB2YXIgZmllbGQgPSBlbC5kYXRhKCdmaWVsZCcpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IGVsLnZhbCgpO1xuXG4gICAgICAgICAgICBfdGhpcy5tb2RlbC5zZXQoZmllbGQsIHZhbCk7XG4gICAgICAgIH0pO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQXNzaWdubWVudFJvdzsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBVc2Vyc0NvbGxlY3Rpb24gPSByZXF1aXJlKCcuL3VzZXJzLWNvbGxlY3Rpb24nKTtcbnZhciBXb3JsZHNDb2xsZWN0aW9uID0gcmVxdWlyZSgnLi93b3JsZHMtY29sbGVjdGlvbicpO1xudmFyIFByb2plY3RNb2RlbCA9IHJlcXVpcmUoJy4vcHJvamVjdC1tb2RlbCcpO1xudmFyIEFzc2lnbmVtbnRSb3cgPSByZXF1aXJlKCcuL2Fzc2lnbm1lbnQtcm93Jyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIEFqYXhRdWV1ZSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvYWpheC1xdWV1ZScpO1xuXG5mdW5jdGlvbiBzZXRFbnZpcm9ubWVudChvcHRpb25zKSB7XG4gICAgZW52LnNldChfLm9taXQob3B0aW9ucywgJ2VsJykpO1xufVxuXG52YXIgQXNzaWdubWVudCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgc2V0RW52aXJvbm1lbnQob3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplKG9wdGlvbnMpO1xufTtcblxuQXNzaWdubWVudC5wcm90b3R5cGUgPSB7XG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLmVsID0gdHlwZW9mIG9wdGlvbnMuZWwgPT09ICdzdHJpbmcnID8gJChvcHRpb25zLmVsKVswXSA6IG9wdGlvbnMuZWw7XG4gICAgICAgIHRoaXMuJGVsID0gJCh0aGlzLmVsKTtcbiAgICAgICAgdGhpcy4kID0gXy5wYXJ0aWFsUmlnaHQoJCwgdGhpcy5lbCk7XG5cbiAgICAgICAgdGhpcy51c2VycyA9IG5ldyBVc2Vyc0NvbGxlY3Rpb24oKTtcbiAgICAgICAgdGhpcy53b3JsZHMgPSBuZXcgV29ybGRzQ29sbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnByb2plY3QgPSBuZXcgUHJvamVjdE1vZGVsKCk7XG5cbiAgICAgICAgXy5iaW5kQWxsKHRoaXMsIFsncmVuZGVyJywgJ3JlbmRlclRhYmxlJywgJ3RvZ2dsZUNvbnRyb2xscycsICdzYXZlRWRpdCcsICdzZWxlY3RBbGwnLCAndXNhc3NpZ25TZWxlY3RlZCcsICdfc2hvd1VwZGF0aW5nJywgJ19oaWRlVXBkYXRpbmcnLCAnYXV0b0Fzc2lnbkFsbCcsICdtYWtlVXNlckluYWN0aXZlJ10pO1xuXG4gICAgICAgIHRoaXMuYmluZEV2ZW50cygpO1xuICAgIH0sXG5cbiAgICBiaW5kRXZlbnRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9uKCd1cGRhdGUnLCAndHInLCB0aGlzLnNhdmVFZGl0KTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2lucHV0OmNoZWNrYm94Om5vdCgjc2VsZWN0LWFsbCknLCB0aGlzLnRvZ2dsZUNvbnRyb2xscyk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICcjc2VsZWN0LWFsbCcsIHRoaXMuc2VsZWN0QWxsKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy51bmFzc2lnbi11c2VyJywgdGhpcy51c2Fzc2lnblNlbGVjdGVkKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy5hdXRvLWFzc2lnbi1hbGwnLCB0aGlzLmF1dG9Bc3NpZ25BbGwpO1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnLm1ha2UtdXNlci1pbmFjdGl2ZScsIHRoaXMubWFrZVVzZXJJbmFjdGl2ZSk7XG4gICAgfSxcblxuICAgIGxvYWQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB2YXIgam9pbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLnNldFVzZXJzQ29sbGVjdGlvbih0aGlzLnVzZXJzKTtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLmpvaW5Vc2VycygpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHJldHVybiAkLndoZW4oXG4gICAgICAgICAgICB0aGlzLndvcmxkcy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy51c2Vycy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy5wcm9qZWN0LmZldGNoKClcbiAgICAgICAgKS50aGVuKGpvaW4pO1xuXG4gICAgfSxcblxuICAgIHNhdmVFZGl0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMud29ybGRzLmZldGNoKClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ29udHJvbHMoKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGF1dG9Bc3NpZ25BbGw6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG4gICAgICAgIHZhciBtYXhVc2VycyA9ICt0aGlzLiQoJyNtYXgtdXNlcnMnKS52YWwoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMud29ybGRzLmF1dG9Bc3NpZ25BbGwoeyBtYXhVc2VyczogbWF4VXNlcnMgfSlcbiAgICAgICAgICAgIC5kb25lKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC5mYWlsKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9LFxuXG4gICAgZ2V0U2VsZWN0ZWRJZHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuJCgndGJvZHkgOmNoZWNrYm94OmNoZWNrZWQnKS5tYXAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICQodGhpcykuZGF0YSgnaWQnKTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGZpbmRSb3dWaWV3czogZnVuY3Rpb24gKGlkcykge1xuICAgICAgICByZXR1cm4gXy5tYXAoaWRzLCBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJvd1ZpZXdzW2lkXTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfSxcblxuICAgIHVuYXNzaWduVXNlcnM6IGZ1bmN0aW9uIChpZHMpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIGZvciBub3cgd2UgbmVlZCB0byBzZXF1ZW5jZSB0aGUgY2FsbHMgdG8gdW5hc3NpZ24gdXNlcnMgZnJvbSB3b3JsZHNcbiAgICAgICAgdmFyIHF1ZXVlID0gbmV3IEFqYXhRdWV1ZSgpO1xuXG4gICAgICAgIF8uZWFjaChpZHMsIGZ1bmN0aW9uICh1c2VySWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyID0gdGhpcy51c2Vycy5nZXRCeUlkKHVzZXJJZCk7XG4gICAgICAgICAgICB1c2VyLnNldCgnd29ybGQnLCAnJyk7XG4gICAgICAgICAgICB1c2VyLnNldCgncm9sZScsICcnKTtcbiAgICAgICAgICAgIHF1ZXVlLmFkZChfLnBhcnRpYWwoXy5iaW5kKHRoaXMud29ybGRzLnVwZGF0ZVVzZXIsIHRoaXMud29ybGRzKSwgdXNlcikpO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIHVzYXNzaWduU2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICB2YXIgaWRzID0gdGhpcy5nZXRTZWxlY3RlZElkcygpO1xuXG4gICAgICAgIHZhciBkb25lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy53b3JsZHMuZmV0Y2goKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9oaWRlVXBkYXRpbmcoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudW5hc3NpZ25Vc2VycyhpZHMpLnRoZW4oZG9uZSk7XG4gICAgfSxcblxuICAgIG1ha2VVc2VySW5hY3RpdmU6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdmFyIGlkcyA9IHRoaXMuZ2V0U2VsZWN0ZWRJZHMoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIG1ha2VVc2Vyc0luYWN0aXZlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJvd3MgPSB0aGlzLmZpbmRSb3dWaWV3cyhpZHMpO1xuICAgICAgICAgICAgLy8gZm9yIG5vdyB3ZSBuZWVkIHRvIHNlcXVlbmNlIHRoZSBjYWxscyB0byBwYXRjaCB0aGUgdXNlcnNcbiAgICAgICAgICAgIC8vIHNpbmNlIHRoZSBBUEkgY2FuIG9ubHkgb3BlcmF0ZSBvbiBvbmUgY2FsbCBwZXIgZ3JvdXAgYXQgYSB0aW1lXG4gICAgICAgICAgICB2YXIgcXVldWUgPSBuZXcgQWpheFF1ZXVlKCk7XG4gICAgICAgICAgICBfLmVhY2gocm93cywgZnVuY3Rpb24gKHZpZXcpIHtcbiAgICAgICAgICAgICAgICB2YXIgdXNlciA9IHZpZXcubW9kZWw7XG4gICAgICAgICAgICAgICAgcXVldWUuYWRkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZpZXcubWFrZUluYWN0aXZlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZXcucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gdGhpcy51bmFzc2lnblVzZXJzKGlkcylcbiAgICAgICAgICAgIC50aGVuKG1ha2VVc2Vyc0luYWN0aXZlKTtcblxuXG4gICAgfSxcblxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiQoJ3RhYmxlIHRib2R5JykuZW1wdHkoKTtcbiAgICAgICAgdGhpcy5yZW5kZXJUYWJsZSgpO1xuICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgIH0sXG5cbiAgICByZW5kZXJUYWJsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJvd1ZpZXdzID0ge307XG4gICAgICAgIHZhciByb3dzID0gW107XG4gICAgICAgIHRoaXMudXNlcnMuZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgQXNzaWduZW1udFJvdyh7IG1vZGVsOiB1LCB3b3JsZHM6IHRoaXMud29ybGRzLCBwcm9qZWN0OiB0aGlzLnByb2plY3QgfSk7XG4gICAgICAgICAgICB0aGlzLnJvd1ZpZXdzW3UuZ2V0KCdpZCcpXSA9IHZpZXc7XG4gICAgICAgICAgICByb3dzLnB1c2godmlldy5yZW5kZXIoKS5lbCk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHRoaXMuJCgndGFibGUgdGJvZHknKS5hcHBlbmQocm93cyk7XG4gICAgfSxcblxuXG4gICAgdXBkYXRlQ29udHJvbHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9sc0ZvclNlbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnVwZGF0ZUF1dG9Bc3NpZ25CdXR0b24oKTtcbiAgICAgICAgdGhpcy51cGRhdGVTdGF0dXMoKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlU3RhdHVzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbmNvbHBsZXRlV29ybGRzID0gdGhpcy53b3JsZHMuZ2V0SW5jb21wbGV0ZVdvcmxkc0NvdW50KCk7XG4gICAgICAgIHZhciB1bmFzc2lnbmVkVXNlcnMgPSB0aGlzLnVzZXJzLmdldFVuYXNzaWduZWRVc2Vyc0NvdW50KCk7XG4gICAgICAgIHZhciB0b3RhbFdvcmxkcyA9IHRoaXMud29ybGRzLnNpemUoKTtcblxuICAgICAgICB2YXIgdXNlcnNUZXh0ID0gdW5hc3NpZ25lZFVzZXJzID8gdW5hc3NpZ25lZFVzZXJzID09PSAxID8gJzEgdXNlciBuZWVkcyBhc3NpZ25tZW50LicgOiB1bmFzc2lnbmVkVXNlcnMgKyAnIHVzZXJzIG5lZWQgYXNzaWdubWVudC4nIDogJ0FsbCB1c2VycyBoYXZlIGJlZW4gYXNzaWduZWQuJztcbiAgICAgICAgdmFyIHdvcmxkc1RleHQgPSAhdG90YWxXb3JsZHMgPyAnTm8gd29ybGRzIGhhdmUgYmVlbiBjcmVhdGVkLicgOiAhaW5jb2xwbGV0ZVdvcmxkcyA/ICdBbGwgd29ybGRzIGFyZSBjb21wbGV0ZS4nIDogaW5jb2xwbGV0ZVdvcmxkcyA9PT0gMSA/ICcxIGluY29tcGxldGUgd29ybGQgbmVlZHMgYXR0ZW50aW9uLicgOiBpbmNvbHBsZXRlV29ybGRzICsgJyBpbmNvbXBsZXRlIHdvcmxkcyBuZWVkIGF0dGVudGlvbi4nO1xuXG4gICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cyAudGV4dCcpLnRleHQodXNlcnNUZXh0KTtcbiAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cyAudGV4dCcpLnRleHQod29ybGRzVGV4dCk7XG5cbiAgICAgICAgaWYgKHVuYXNzaWduZWRVc2Vycykge1xuICAgICAgICAgICAgdGhpcy4kKCcjdXNlcnMtc3RhdHVzJykuYWRkQ2xhc3MoJ2luY29tcGxldGUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5jb2xwbGV0ZVdvcmxkcyB8fCAhdG90YWxXb3JsZHMpIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3dvcmxkcy1zdGF0dXMnKS5hZGRDbGFzcygnaW5jb21wbGV0ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLiQoJy5zdGF0dXMtd2lkZ2V0JykuYWRkQ2xhc3MoJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQ29udHJvbHNGb3JTZWxlY3Rpb246IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG51bVNlbGVjdGVkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpLmxlbmd0aDtcbiAgICAgICAgdGhpcy4kKCcuY29tcG9uZW50LmNvbnRyb2xzJylbbnVtU2VsZWN0ZWQgPyAnYWRkQ2xhc3MnIDogJ3JlbW92ZUNsYXNzJ10oJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQXV0b0Fzc2lnbkJ1dHRvbjogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIGlmICh0aGlzLnByb2plY3QuaXNEeW5hbWljQXNzaWdubWVudCgpKSB7XG4gICAgICAgICAgICB2YXIgaGFzUm9sZXMgPSB0aGlzLnByb2plY3QuaGFzUm9sZXMoKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5zaW5nbGUnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYycpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5keW5hbWljLW5vLXJvbGVzLXRleHQnKVtoYXNSb2xlcyA/ICdoaWRlJyA6ICdzaG93J10oKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpW2hhc1JvbGVzID8gJ2hpZGUnIDogJ3Nob3cnXSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLmR5bmFtaWMnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYy1uby1yb2xlcy10ZXh0JykuaGlkZSgpO1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLnNpbmdsZScpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpLnNob3coKTtcblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudXNlcnMuYWxsVXNlcnNBc3NpZ25lZCgpKSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLnJlbW92ZUNsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLmFkZENsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc2VsZWN0QWxsOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICB0aGlzLiQoJ3Rib2R5IDpjaGVja2JveCcpLnByb3AoJ2NoZWNrZWQnLCBlLnRhcmdldC5jaGVja2VkKTtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICB0b2dnbGVDb250cm9sbHM6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB0b3RhbCA9IHRoaXMuJCgndGJvZHkgOmNoZWNrYm94Jyk7XG4gICAgICAgIHZhciBjaGVja2VkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpO1xuXG4gICAgICAgIGlmICh0b3RhbC5sZW5ndGggPT09IGNoZWNrZWQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykuYXR0cignY2hlY2tlZCcsICdjaGVja2VkJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykucmVtb3ZlQXR0cignY2hlY2tlZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICBfc2hvd1VwZGF0aW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLmNzcyh7IG9wYWNpdHk6IDAuNCB9KTtcbiAgICB9LFxuXG4gICAgX2hpZGVVcGRhdGluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5jc3MoeyBvcGFjaXR5OiAxIH0pO1xuICAgIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBc3NpZ25tZW50OyIsIid1c2Ugc3RyaWN0JztcblxudmFyIEJhc2VDb2xsZWN0aW9uID0gZnVuY3Rpb24gKG1vZGVscywgb3B0aW9ucykge1xuICAgIHRoaXMuX21vZGVscyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlQ29sbGVjdGlvbi5wcm90b3R5cGUsIHtcbiAgICBpZEF0dHJpYnV0ZTogJ2lkJyxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uIChtb2RlbHMsIG9wdGlvbnMpIHtcbiAgICB9LFxuXG4gICAgY3JlYXRlOiBmdW5jdGlvbiAoYXR0ciwgb3B0aW9ucykge1xuICAgICAgICB2YXIgbSA9IG5ldyB0aGlzLm1vZGVsKGF0dHIsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnNldChtKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAobW9kZWxzLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMuX21vZGVscy5sZW5ndGggPSAwO1xuICAgICAgICB0aGlzLnNldChtb2RlbHMpO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uIChtb2RlbCkge1xuICAgICAgICBfLnJlbW92ZSh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbSA9PT0gbW9kZWw7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGRlbGV0ZSBtb2RlbC5jb2xsZWN0aW9uO1xuXG4gICAgICAgIHJldHVybiBtb2RlbDtcbiAgICB9LFxuXG4gICAgc2V0OiBmdW5jdGlvbiAobW9kZWxzKSB7XG4gICAgICAgIGlmICghbW9kZWxzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBtb2RlbHMgPSBbXS5jb25jYXQobW9kZWxzKTtcblxuICAgICAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIF8uZWFjaChtb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICBpZiAoIShtIGluc3RhbmNlb2YgdGhpcy5tb2RlbCkpIHtcbiAgICAgICAgICAgICAgICBtID0gbmV3IHRoaXMubW9kZWwobSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG0uY29sbGVjdGlvbiA9IHRoaXM7XG5cbiAgICAgICAgICAgIHRoaXMuX21vZGVscy5wdXNoKG0pO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICB0aGlzLnNvcnQuY2FsbCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gbW9kZWxzO1xuICAgIH0sXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBiLl9kYXRhW3RoaXMuaWRBdHRyaWJ1dGVdIC0gYS5fZGF0YVt0aGlzLmlkQXR0cmlidXRlXTtcbiAgICB9LFxuXG4gICAgc29ydDogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLl9tb2RlbHMgPSB0aGlzLl9tb2RlbHMuc29ydCh0aGlzLnNvcnRGbi5iaW5kKHRoaXMpKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzO1xuICAgIH0sXG5cbiAgICBnZXRCeUlkOiBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgcmV0dXJuIF8uZmluZCh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbS5nZXQodGhpcy5pZEF0dHJpYnV0ZSkgPT09IGlkO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgZWFjaDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uZWFjaCh0aGlzLl9tb2RlbHMsIGNiLCBjdHggfHwgdGhpcyk7XG4gICAgfSxcblxuICAgIGFsbDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uYWxsKHRoaXMuX21vZGVscywgY2IsIGN0eCB8fCB0aGlzKTtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBfLmludm9rZSh0aGlzLl9tb2RlbHMsICd0b0pTT04nKTtcbiAgICB9LFxuXG4gICAgZmluZDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbmQodGhpcy5fbW9kZWxzLCBmbik7XG4gICAgfSxcblxuICAgIGZpbHRlcjogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbHRlcih0aGlzLl9tb2RlbHMsIGZuKTtcbiAgICB9LFxuXG4gICAgc2l6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgbWFwOiBmdW5jdGlvbiAoZm4sIGN0eCkge1xuICAgICAgICByZXR1cm4gXy5tYXAodGhpcy5fbW9kZWxzLCBmdW5jdGlvbiAobW9kZWwpIHtcbiAgICAgICAgICAgIHJldHVybiBmbi5jYWxsKGN0eCwgbW9kZWwudG9KU09OKCkpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgcGx1Y2s6IGZ1bmN0aW9uIChmaWVsZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBtW2ZpZWxkXTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlQ29sbGVjdGlvbjsiLCIndXNlIHN0cmljdCc7XG5cblxudmFyIEJhc2VNb2RlbCA9IGZ1bmN0aW9uIChhdHRyLCBvcHRpb25zKSB7XG4gICAgYXR0ciA9IF8uZGVmYXVsdHMoe30sIGF0dHIsIF8ucmVzdWx0KHRoaXMsICdkZWZhdWx0cycpKTtcbiAgICB0aGlzLl9kYXRhID0ge307XG4gICAgdGhpcy5zZXQoYXR0ciwgb3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlTW9kZWwucHJvdG90eXBlLCB7XG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKGF0dHIsIG9wdGlvbnMpIHtcblxuICAgIH0sXG5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbCwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChrZXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWw7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBfLmV4dGVuZCh0aGlzLl9kYXRhLCBhdHRycyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGdldDogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YVtrZXldO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jb2xsZWN0aW9uLnJlbW92ZSh0aGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICB0b0pTT046IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGE7XG4gICAgfSxcblxuICAgIHBpY2s6IGZ1bmN0aW9uIChrZXlzKSB7XG4gICAgICAgIHJldHVybiBfLnBpY2sodGhpcy5fZGF0YSwga2V5cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlTW9kZWw7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZW52ID0ge1xuICAgIGFjY291bnQ6ICcnLFxuICAgIHByb2plY3Q6ICcnLFxuICAgIGdyb3VwOiAnJyxcbiAgICBncm91cElkOiAnJyxcbiAgICB0b2tlbjogJycsXG4gICAgc2VydmVyOiB7XG4gICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgcHJvdG9jb2w6ICdodHRwcydcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBzZXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGVudiA9IF8ubWVyZ2UoZW52LCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBlbnY7XG4gICAgfVxufTsiLCIoZnVuY3Rpb24gKCkge1xuICAgICd1c2Ugc3RyaWN0JztcbiAgICB2YXIgQXBwID0gcmVxdWlyZSgnLi9hc3NpZ25tZW50LmpzJyk7XG5cbiAgICB3aW5kb3cuZm9yaW8gPSB3aW5kb3cuZm9yaW8gfHwge307XG4gICAgd2luZG93LmZvcmlvLk11bHRpcGxheWVyQXNzaWdubWVudENvbXBvbmVudCA9IEFwcDtcbn0pKCk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBzZXJ2aWNlTG9jYXRvciA9IHJlcXVpcmUoJy4vc2VydmljZS1sb2NhdG9yJyk7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG4vLyB2YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBpc0R5bmFtaWNBc3NpZ25tZW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldCgnd29ybGRzJykgPT09ICdkeW5hbWljJztcbiAgICB9LFxuXG4gICAgaGFzUm9sZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJvbGVzID0gdGhpcy5nZXQoJ3JvbGVzJyk7XG4gICAgICAgIHJldHVybiByb2xlcyAmJiAhIXJvbGVzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGFwaSA9IHNlcnZpY2VMb2NhdG9yLndvcmxkQXBpKCk7XG5cbiAgICAgICAgcmV0dXJuIGFwaS5nZXRQcm9qZWN0U2V0dGluZ3MoKS50aGVuKGZ1bmN0aW9uIChzZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5zZXQoc2V0dGluZ3MpO1xuICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cbn0pOyIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVudiA9IHJlcXVpcmUoJy4vZGVmYXVsdHMuanMnKTtcblxudmFyIGNhY2hlID0ge307XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHdvcmxkQXBpOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghY2FjaGUud29ybGRBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLndvcmxkQXBpID0gbmV3IEYuc2VydmljZS5Xb3JsZChlbnYuZ2V0KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLndvcmxkQXBpO1xuICAgIH0sXG5cbiAgICBtZW1iZXJBcGk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFjYWNoZS5tZW1iZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLm1lbWJlckFwaSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKF8ucGljayhlbnYuZ2V0KCksIFsnZ3JvdXBJZCcsICdzZXJ2ZXInXSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLm1lbWJlckFwaTtcbiAgICB9LFxuXG4gICAgdXNlckFwaTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIWNhY2hlLnVzZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLnVzZXJBcGkgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoXy5waWNrKGVudi5nZXQoKSwgWydhY2NvdW50JywgJ3NlcnZlciddKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2FjaGUudXNlckFwaTtcbiAgICB9XG59OyIsImV4cG9ydHNbXCJlZGl0LXVzZXItcm93XCJdID0gZnVuY3Rpb24ob2JqKSB7XG5vYmogfHwgKG9iaiA9IHt9KTtcbnZhciBfX3QsIF9fcCA9ICcnLCBfX2UgPSBfLmVzY2FwZSwgX19qID0gQXJyYXkucHJvdG90eXBlLmpvaW47XG5mdW5jdGlvbiBwcmludCgpIHsgX19wICs9IF9fai5jYWxsKGFyZ3VtZW50cywgJycpIH1cbndpdGggKG9iaikge1xuX19wICs9ICc8dGQ+PGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGNsYXNzPVwic2VsZWN0XCIgZGF0YS1pZD1cIicgK1xuKChfX3QgPSAoIGlkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+PC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cIndvcmxkc1wiIGNsYXNzPVwiZm9ybS1jb250cm9sXCIgZGF0YS1maWVsZD1cIndvcmxkXCI+XFxuXFxuICAgICc7XG4gXy5lYWNoKHdvcmxkcywgZnVuY3Rpb24gKHcpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHcgPT09IHdvcmxkID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIicgK1xuKChfX3QgPSAoIG5ld1dvcmxkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiIGNsYXNzPVwibmV3LXdvcmxkLXRleHRcIj48aT4nICtcbigoX190ID0gKCBuZXdXb3JsZCApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbicgLSBOZXcgLTwvaT48L29wdGlvbj5cXG4gICAgPC9zZWxlY3Q+XFxuPC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cInJvbGVzXCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBkYXRhLWZpZWxkPVwicm9sZVwiPlxcbiAgICAnO1xuIF8uZWFjaChyb2xlcywgZnVuY3Rpb24gKHIpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHIgPT09IHJvbGUgPyAnc2VsZWN0ZWQnIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPicgK1xuKChfX3QgPSAoIHIgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC9vcHRpb24+XFxuICAgICc7XG4gfSk7IDtcbl9fcCArPSAnXFxuXFxuICAgICc7XG4gXy5lYWNoKG9wdGlvbmFsUm9sZXMsIGZ1bmN0aW9uIChyKSB7IDtcbl9fcCArPSAnXFxuICAgICAgICA8b3B0aW9uIHZhbHVlPVwiJyArXG4oKF9fdCA9ICggciApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbidcIiAnICtcbigoX190ID0gKCByID09PSByb2xlID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJyA8aT4oT3B0aW9uYWwpPC9pPjwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICA8L3NlbGVjdD5cXG48L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi10b29scyBidG4tc2F2ZSBzYXZlXCI+U2F2ZTwvYnV0dG9uPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi10b29scyBidG4tY2FuY2VsIGNhbmNlbFwiPkNhbmNlbDwvYnV0dG9uPlxcbjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTtcbmV4cG9ydHNbXCJ1c2VyLXJvd1wiXSA9IGZ1bmN0aW9uKG9iaikge1xub2JqIHx8IChvYmogPSB7fSk7XG52YXIgX190LCBfX3AgPSAnJywgX19lID0gXy5lc2NhcGU7XG53aXRoIChvYmopIHtcbl9fcCArPSAnPHRkPjxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cInNlbGVjdFwiIGRhdGEtaWQ9XCInICtcbigoX190ID0gKCBpZCkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggIWlzV29ybGRDb21wbGV0ZSA/ICc8ZW0gY2xhc3M9XCJmLWljb24gZi13YXJuaW5nXCI+PC9lbT4nIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggd29ybGQgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggcm9sZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPjxidXR0b24gY2xhc3M9XCJidG4gZWRpdCBidG4tZWRpdCBidG4tdG9vbHMgYXV0by1oaWRlXCI+RWRpdDwvYnV0dG9uPjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBkZWZhdWx0czoge1xuICAgICAgICB3b3JsZDogJycsXG4gICAgICAgIHJvbGU6ICcnLFxuICAgICAgICBhY3RpdmU6IHRydWUsXG4gICAgICAgIGlzV29ybGRDb21wbGV0ZTogdHJ1ZSxcbiAgICAgICAgZmlyc3ROYW1lOiAnJyxcbiAgICAgICAgbGFzdE5hbWU6ICcnXG4gICAgfSxcblxuICAgIG1ha2VBY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gbWVtYmVyQXBpLm1ha2VVc2VyQWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBtYWtlSW5hY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBmYWxzZSk7XG5cbiAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5tYWtlVXNlckluYWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cblxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcblxudmFyIE1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcblxuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBtb2RlbDogTW9kZWwsXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHZhciBhdyA9IGEuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBidyA9IGIuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIGlmIChhdyAhPT0gYncpIHtcbiAgICAgICAgICAgIHJldHVybiBhdyA8IGJ3ID8gLTEgOiAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGIuZ2V0KCd1c2VyTmFtZScpID4gYS5nZXQoJ3VzZXJOYW1lJykgPyAtMSA6IDE7XG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJC5hamF4U2V0dXAoe1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIGVudi5nZXQoKS50b2tlblxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgYWxsVXNlcnNBc3NpZ25lZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hbGwoZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiAhIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0VW5hc3NpZ25lZFVzZXJzQ291bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmlsdGVyKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICByZXR1cm4gIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KS5sZW5ndGg7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBncm91cElkID0gZW52LmdldCgpLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGdldEdyb3VwVXNlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbWVtYmVyQXBpID0gc2VydmljZUxvY2F0b3IubWVtYmVyQXBpKCk7XG4gICAgICAgICAgICB2YXIgdXNlckFwaSA9IHNlcnZpY2VMb2NhdG9yLnVzZXJBcGkoKTtcblxuICAgICAgICAgICAgdmFyIGxvYWRHcm91cE1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5nZXRHcm91cERldGFpbHMoKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBsb2FkVXNlcnNJbmZvID0gZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vbkZhY0FuZEFjdGl2ZSA9IGZ1bmN0aW9uICh1KSB7IHJldHVybiB1LmFjdGl2ZSAmJiB1LnJvbGUgIT09ICdmYWNpbGl0YXRvcic7IH07XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJzID0gXy5wbHVjayhfLmZpbHRlcihncm91cC5tZW1iZXJzLCBub25GYWNBbmRBY3RpdmUpLCAndXNlcklkJyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVzZXJBcGkuZ2V0KHsgaWQ6IHVzZXJzIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGxvYWRHcm91cE1lbWJlcnMoKVxuICAgICAgICAgICAgICAgIC50aGVuKGxvYWRVc2Vyc0luZm8pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgZ2V0R3JvdXBVc2VycygpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAodXNlcnMpIHtcbiAgICAgICAgICAgICAgICB1c2VycyA9IF8ubWFwKHVzZXJzLCBmdW5jdGlvbiAodSkgeyByZXR1cm4gXy5leHRlbmQodSwgeyBncm91cElkOiBncm91cElkIH0pOyB9KTtcbiAgICAgICAgICAgICAgICBfdGhpcy5zZXQodXNlcnMpO1xuICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHVzZXJzLCBfdGhpcyk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9XG5cbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBkZWZhdWx0czoge1xuICAgICAgICB1c2VyczogbnVsbCxcbiAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX19zdXBlci5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgdGhpcy5fZGF0YS51c2VycyA9IHRoaXMuX2RhdGEudXNlcnMgfHwgW107XG5cbiAgICAgICAgdGhpcy5fd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuXG4gICAgICAgIHZhciBpZCA9IHRoaXMuZ2V0KCdpZCcpO1xuICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgYWRkVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIHVzZXJzLnB1c2godXNlcik7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuc2F2ZSgpO1xuICAgIH0sXG5cbiAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlcikge1xuICAgICAgICB2YXIgaWQgPSB0aGlzLmdldCgnaWQnKTtcbiAgICAgICAgdmFyIGNoZWNrV29ybGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuZ2V0KCd1c2VycycpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSkuZGVsZXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICBfLnJlbW92ZSh0aGlzLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiB1LmdldCgnaWQnKSA9PT0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl93b3JsZEFwaVxuICAgICAgICAgICAgLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSlcbiAgICAgICAgICAgIC5yZW1vdmVVc2VyKHsgdXNlcklkOiB1c2VyLmdldCgnaWQnKSB9KVxuICAgICAgICAgICAgLnRoZW4oY2hlY2tXb3JsZCk7XG4gICAgfSxcblxuICAgIHNhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIG1hcFVzZXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIF8ubWFwKHRoaXMuZ2V0KCd1c2VycycpLCBmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgICAgIHZhciByZXMgPSB7IHVzZXJJZDogdS5nZXQoJ2lkJykgfTtcbiAgICAgICAgICAgICAgICB2YXIgcm9sZSA9IHUuZ2V0KCdyb2xlJyk7XG5cbiAgICAgICAgICAgICAgICBpZiAocm9sZSkge1xuICAgICAgICAgICAgICAgICAgICByZXMucm9sZSA9IHJvbGU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIGNyZWF0ZVdvcmxkID0gXy5wYXJ0aWFsKHRoaXMuX3dvcmxkQXBpLmNyZWF0ZSwgdGhpcy5waWNrKFsnbW9kZWwnLCAnbmFtZScsICdtaW5Vc2VycyddKSk7XG4gICAgICAgIHZhciBhZGRVc2VycyA9IF8ucGFydGlhbChfdGhpcy5fd29ybGRBcGkuYWRkVXNlcnMsIG1hcFVzZXJzKCksIHsgZmlsdGVyOiBfdGhpcy5nZXQoJ2lkJykgfSk7XG4gICAgICAgIHZhciBzYXZlZFVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIGlmICh0aGlzLmlzTmV3KCkpIHtcbiAgICAgICAgICAgIC8vIHdlIG5lZWQgdG8gY3JlYXRlIHRoZSB3b3JsZCBpbiB0aGUgQVBJIGFuZCB0aGVuIGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVXb3JsZCgpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNldCh3b3JsZCk7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLl93b3JsZEFwaS51cGRhdGVDb25maWcoeyBmaWx0ZXI6IHdvcmxkLmlkIH0pO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oYWRkVXNlcnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHVzZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHNpbmNlIHdlIHJlLXNldCB0aGUgd29ybGQsIHJlLXNldCB0aGUgdXNlcnNcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuc2V0KCd1c2VycycsIHNhdmVkVXNlcnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gdGhlIHdvcmxkIGlzIGFscmVhZHkgY3JlYXRlZCBqdXN0IGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBhZGRVc2VycygpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGlzTmV3OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5nZXQoJ2xhc3RNb2RpZmllZCcpO1xuICAgIH1cblxufSk7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgTW9kZWwgPSByZXF1aXJlKCcuL3dvcmxkLW1vZGVsJyk7XG52YXIgVXNlck1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG52YXIgZG9uZUZuID0gZnVuY3Rpb24gKGR0ZCwgYWZ0ZXIpIHtcbiAgICByZXR1cm4gXy5hZnRlcihhZnRlciwgZHRkLnJlc29sdmUpO1xufTtcblxudmFyIHdvcmxkQXBpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgbW9kZWw6IE1vZGVsLFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBfX3N1cGVyLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuICAgIH0sXG5cbiAgICBhdXRvQXNzaWduQWxsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gd29ybGRBcGkuYXV0b0Fzc2lnbihvcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzZXQodGhpcy5wYXJzZSh3b3JsZHMpKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGdldEluY29tcGxldGVXb3JsZHNDb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24gKHcpIHtcbiAgICAgICAgICAgIHJldHVybiAhdy5nZXQoJ2NvbXBsZXRlJyk7XG4gICAgICAgIH0pLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgdXBkYXRlVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHdvcmxkTmFtZSA9IHVzZXIuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgcHJldldvcmxkID0gdGhpcy5nZXRXb3JsZEJ5VXNlcih1c2VyKTtcbiAgICAgICAgdmFyIGN1cldvcmxkID0gdGhpcy5nZXRPckNyZWF0ZVdvcmxkKHdvcmxkTmFtZSk7XG4gICAgICAgIHZhciBkb25lID0gZG9uZUZuKGR0ZCwgMSk7XG5cbiAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUncyBhbnl0aGluZyB0byBkb1xuICAgICAgICBpZiAoIXByZXZXb3JsZCAmJiAhY3VyV29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiBkdGQucmVzb2x2ZSgpLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwcmV2V29ybGQpIHtcbiAgICAgICAgICAgIHByZXZXb3JsZC5yZW1vdmVVc2VyKHVzZXIpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY3VyV29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjdXJXb3JsZC5hZGRVc2VyKHVzZXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAudGhlbihkb25lKTtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJXb3JsZCkge1xuICAgICAgICAgICAgY3VyV29ybGQuYWRkVXNlcih1c2VyKVxuICAgICAgICAgICAgICAgIC50aGVuKGRvbmUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldE9yQ3JlYXRlV29ybGQ6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgaWYgKCF3b3JsZE5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB3b3JsZCA9IHRoaXMuZ2V0V29yZEJ5TmFtZSh3b3JsZE5hbWUpO1xuXG4gICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgIHdvcmxkID0gdGhpcy5jcmVhdGUoeyBuYW1lOiB3b3JsZE5hbWUgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gd29ybGQ7XG4gICAgfSxcblxuICAgIGdldFdvcmRCeU5hbWU6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmluZChmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiB3b3JsZC5nZXQoJ25hbWUnKSA9PT0gd29ybGROYW1lO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGRCeVVzZXI6IGZ1bmN0aW9uICh1c2VyKSB7XG4gICAgICAgIGlmICghdXNlci5nZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZ2V0V29ybGRCeVVzZXIgZXhwZWN0ZXMgYSBtb2RlbCAoJyArIHVzZXIgKyAnKScpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGlkID0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFdvcmxkQnlVc2VySWQoaWQpO1xuICAgIH0sXG5cbiAgICBnZXRXb3JsZEJ5VXNlcklkOiBmdW5jdGlvbiAodXNlcklkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZpbmQoZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICByZXR1cm4gXy5maW5kKHdvcmxkLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdS5nZXQoJ2lkJykgPT09IHVzZXJJZDtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGROYW1lczogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wbHVjaygnbmFtZScpO1xuICAgIH0sXG5cbiAgICBnZXROZXh0V29ybGROYW1lOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBwYWQgPSBmdW5jdGlvbiAobnVtLCBwbGFjZXMpIHtcbiAgICAgICAgICAgIHZhciB6ZXJvcyA9ICcwMDAwMDAwMDAwMDAwMDAwMDAnO1xuICAgICAgICAgICAgdmFyIGRpZ2l0cyA9IG51bS50b1N0cmluZygpLmxlbmd0aDtcbiAgICAgICAgICAgIHZhciBuZWVkZWQgPSBwbGFjZXMgLSBkaWdpdHM7XG4gICAgICAgICAgICByZXR1cm4gemVyb3Muc3Vic3RyKDAsIG5lZWRlZCkgKyBudW07XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHdvcmxkcyA9IHRoaXMuZ2V0V29ybGROYW1lcygpO1xuXG4gICAgICAgIGlmICghd29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuICdXb3JsZDAwMSc7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcHJvcGVyTmFtZXMgPSBfLmZpbHRlcih3b3JsZHMsIGZ1bmN0aW9uICh3KSB7IHJldHVybiAvV29ybGRcXGRcXGRcXGQvLnRlc3Qodyk7IH0pLnNvcnQoKTtcbiAgICAgICAgdmFyIGxhc3RXb3JsZCA9IHByb3Blck5hbWVzW3Byb3Blck5hbWVzLmxlbmd0aCAtIDFdO1xuICAgICAgICB2YXIgbnVtV29ybGQgPSArbGFzdFdvcmxkLm1hdGNoKC9Xb3JsZChcXGRcXGRcXGQpLylbMV07XG4gICAgICAgIHJldHVybiAnV29ybGQnICsgcGFkKG51bVdvcmxkICsgMSwgMyk7XG4gICAgfSxcblxuICAgIHNldFVzZXJzQ29sbGVjdGlvbjogZnVuY3Rpb24gKHVzZXJzQ29sbGVjdGlvbikge1xuICAgICAgICB0aGlzLnVzZXJzQ29sbGVjdGlvbiA9IHVzZXJzQ29sbGVjdGlvbjtcbiAgICB9LFxuXG4gICAgam9pblVzZXJzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1c2Vyc0hhc2ggPSB7fTtcbiAgICAgICAgdmFyIHVzZXJzQ29sbGVjdGlvbiA9IHRoaXMudXNlcnNDb2xsZWN0aW9uO1xuICAgICAgICB1c2Vyc0NvbGxlY3Rpb24uZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdS5zZXQoeyBpc1dvcmxkQ29tcGxldGU6IHRydWUgfSk7XG4gICAgICAgICAgICByZXR1cm4gKHVzZXJzSGFzaFt1LmdldCgnaWQnKV0gPSB1KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5lYWNoKGZ1bmN0aW9uICh3LCBpKSB7XG4gICAgICAgICAgICB2YXIgbmFtZSA9IHcuZ2V0KCduYW1lJyk7XG4gICAgICAgICAgICB2YXIgaXNDb21wbGV0ZSA9IHcuZ2V0KCdjb21wbGV0ZScpO1xuICAgICAgICAgICAgdy5zZXQoeyBpbmRleDogaSwgbmFtZTogbmFtZSB8fCAoaSArIDEpICsgJycgfSk7XG4gICAgICAgICAgICBfLmVhY2gody5nZXQoJ3VzZXJzJyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgaWYgKHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldKSB7XG4gICAgICAgICAgICAgICAgICAgIHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldLnNldCh7IHdvcmxkOiBuYW1lLCByb2xlOiB1LmdldCgncm9sZScpLCBpc1dvcmxkQ29tcGxldGU6IGlzQ29tcGxldGUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHVzZXJzQ29sbGVjdGlvbi5zb3J0KCk7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB3b3JsZEFwaS5saXN0KClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc2V0KHRoaXMucGFyc2Uod29ybGRzKSk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBwYXJzZTogZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICBpZiAod29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgd29ybGRzID0gXy5tYXAod29ybGRzLCBmdW5jdGlvbiAodykge1xuICAgICAgICAgICAgICAgIHZhciB1c2VycyA9IF8ubWFwKHcudXNlcnMsIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGluIHRoZSB3b3JsZCBhcGkgdXNlcnMgSWRzIGNvbWVzIGFzIHVzZXJJZFxuICAgICAgICAgICAgICAgICAgICAvLyBtYWtlIHN1cmUgd2UgYWRkIGl0IGFzIGlkIHNvIHdlIGNhbiB1c2UgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIHNhbWUgY29kZSB0byBhY2Nlc3MgbW9kZWxzIHRoYXQgY29tZSBmcm9tIHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyBtZW1iZXIvbG9jYWwgYXBpIGFzIHdpdGggdGhlIHdvcmxkIGFwaVxuICAgICAgICAgICAgICAgICAgICB1LmlkID0gdS51c2VySWQ7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVXNlck1vZGVsKHUpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgdy51c2VycyA9IHVzZXJzO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHc7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB3b3JsZHM7XG4gICAgfVxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuKiBVdGlsaXR5IGNsYXNzIHRvIG1ha2UgYWpheCBjYWxscyBzZXF1ZW5jaWFsXG4qL1xuZnVuY3Rpb24gQWpheFF1ZXVlICgpIHtcbiAgICB0aGlzLnF1ZXVlID0gW107XG59XG5cbiQuZXh0ZW5kKEFqYXhRdWV1ZS5wcm90b3R5cGUsIHtcbiAgICBhZGQ6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICByZXR1cm4gdGhpcy5xdWV1ZS5wdXNoKGZuKTtcbiAgICB9LFxuXG4gICAgZXhlY3V0ZTogZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgY29udGV4dCA9IGNvbnRleHQgfHwgdGhpcztcblxuICAgICAgICBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgICAgICAgaWYgKF90aGlzLnF1ZXVlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBmbiA9IF90aGlzLnF1ZXVlLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgICAgICBmbi5jYWxsKGNvbnRleHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKG5leHQpXG4gICAgICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbmV4dCgpO1xuXG4gICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQWpheFF1ZXVlOyIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiJdfQ== +//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Fzc2lnbm1lbnQtcm93LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9hc3NpZ25tZW50LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9iYXNlLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Jhc2UtbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2RlZmF1bHRzLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9pbmRleC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvcHJvamVjdC1tb2RlbC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvc2VydmljZS1sb2NhdG9yLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy90ZW1wbGF0ZXMuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXItbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXJzLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3dvcmxkLW1vZGVsLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy93b3JsZHMtY29sbGVjdGlvbi5qcyIsInNyYy91dGlsL2FqYXgtcXVldWUuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCc7XG5cbnZhciB0ZW1wbGF0ZXMgPSByZXF1aXJlKCcuL3RlbXBsYXRlcycpO1xuXG52YXIgQXNzaWdubWVudFJvdyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy4kZWwgPSAkKCc8dHI+Jyk7XG4gICAgdGhpcy5lbCA9IHRoaXMuJGVsWzBdO1xuICAgIHRoaXMuJCA9IF8ucGFydGlhbFJpZ2h0KCQsIHRoaXMuJGVsKTtcblxuICAgIHRoaXMubW9kZWwgPSBvcHRpb25zLm1vZGVsO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy53b3JsZHMgPSBvcHRpb25zLndvcmxkcztcbiAgICB0aGlzLnByb2plY3QgPSBvcHRpb25zLnByb2plY3Q7XG5cbiAgICBfLmJpbmRBbGwodGhpcywgWydzZXRFZGl0TW9kZScsICdyZW1vdmVFZGl0TW9kZScsICdzYXZlRWRpdCcsICdjYW5jZWxFZGl0JywgJ3VwZGF0ZURhdGEnXSk7XG5cbiAgICB0aGlzLmJpbmRFdmVudHMoKTtcblxufTtcblxuXy5leHRlbmQoQXNzaWdubWVudFJvdy5wcm90b3R5cGUsIHtcblxuICAgIHRlbXBsYXRlOiB0ZW1wbGF0ZXNbJ3VzZXItcm93J10sXG5cbiAgICBlZGl0VGVtcGxhdGU6IHRlbXBsYXRlc1snZWRpdC11c2VyLXJvdyddLFxuXG4gICAgYmluZEV2ZW50czogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnYnV0dG9uLmVkaXQnLCB0aGlzLnNldEVkaXRNb2RlKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2J1dHRvbi5zYXZlJywgdGhpcy5zYXZlRWRpdCk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICdidXR0b24uY2FuY2VsJywgdGhpcy5jYW5jZWxFZGl0KTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9mZignY2xpY2snLCBudWxsLCBudWxsKTtcbiAgICAgICAgLy8gdGhpcyBvbmx5IGdpdmVzIGEgZGVsYXkgdG8gcmVtb3ZlIHRoZSB0clxuICAgICAgICAvLyBhbmltYXRpb24gb2YgaGVpZ2h0IG9mIHRoZSB0ciBkb2VzIG5vdCB3b3JrXG4gICAgICAgIHRoaXMuJCgnOmNoZWNrYm94JykuYXR0cignY2hlY2tlZCcsIGZhbHNlKTtcbiAgICAgICAgdGhpcy4kZWxcbiAgICAgICAgICAgIC5jc3MoeyBvcGFjaXR5OiAwLjMgfSlcbiAgICAgICAgICAgIC5hbmltYXRlKHsgaGVpZ2h0OiAwIH0sIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMzAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIG1ha2VJbmFjdGl2ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tb2RlbC5tYWtlSW5hY3RpdmUoKTtcbiAgICB9LFxuXG4gICAgc2V0RWRpdE1vZGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5tb2RlbC5zZXQoJ2VkaXQtbW9kZScsIHRydWUpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICByZW1vdmVFZGl0TW9kZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLm1vZGVsLnNldCgnZWRpdC1tb2RlJywgZmFsc2UpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICBzYXZlRWRpdDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB0aGlzLnVwZGF0ZURhdGEoKTtcbiAgICAgICAgdGhpcy53b3JsZHNcbiAgICAgICAgICAgIC51cGRhdGVVc2VyKHRoaXMubW9kZWwpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMucmVtb3ZlRWRpdE1vZGUoKTtcbiAgICAgICAgICAgICAgICBfdGhpcy4kZWwudHJpZ2dlcigndXBkYXRlJywgX3RoaXMpO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGNhbmNlbEVkaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVFZGl0TW9kZSgpO1xuICAgIH0sXG5cbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHRlbXBsID0gdGhpcy5tb2RlbC5nZXQoJ2VkaXQtbW9kZScpID8gdGhpcy5lZGl0VGVtcGxhdGUgOiB0aGlzLnRlbXBsYXRlO1xuICAgICAgICB2YXIgdm0gPSBfLmV4dGVuZCh7XG4gICAgICAgICAgICByb2xlczogdGhpcy5wcm9qZWN0LmdldCgncm9sZXMnKSxcbiAgICAgICAgICAgIG9wdGlvbmFsUm9sZXM6IHRoaXMucHJvamVjdC5nZXQoJ29wdGlvbmFsUm9sZXMnKSxcbiAgICAgICAgICAgIHdvcmxkczogdGhpcy53b3JsZHMuZ2V0V29ybGROYW1lcygpLFxuICAgICAgICAgICAgbmV3V29ybGQ6IHRoaXMud29ybGRzLmdldE5leHRXb3JsZE5hbWUoKVxuICAgICAgICB9LCB0aGlzLm1vZGVsLnRvSlNPTigpKTtcblxuICAgICAgICB0aGlzLiRlbC5odG1sKHRlbXBsKHZtKSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIHVwZGF0ZURhdGE6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdGhpcy4kKCdbZGF0YS1maWVsZF0nKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBlbCA9ICQodGhpcyk7XG4gICAgICAgICAgICB2YXIgZmllbGQgPSBlbC5kYXRhKCdmaWVsZCcpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IGVsLnZhbCgpO1xuXG4gICAgICAgICAgICBfdGhpcy5tb2RlbC5zZXQoZmllbGQsIHZhbCk7XG4gICAgICAgIH0pO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQXNzaWdubWVudFJvdzsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBVc2Vyc0NvbGxlY3Rpb24gPSByZXF1aXJlKCcuL3VzZXJzLWNvbGxlY3Rpb24nKTtcbnZhciBXb3JsZHNDb2xsZWN0aW9uID0gcmVxdWlyZSgnLi93b3JsZHMtY29sbGVjdGlvbicpO1xudmFyIFByb2plY3RNb2RlbCA9IHJlcXVpcmUoJy4vcHJvamVjdC1tb2RlbCcpO1xudmFyIEFzc2lnbmVtbnRSb3cgPSByZXF1aXJlKCcuL2Fzc2lnbm1lbnQtcm93Jyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIEFqYXhRdWV1ZSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvYWpheC1xdWV1ZScpO1xuXG5mdW5jdGlvbiBzZXRFbnZpcm9ubWVudChvcHRpb25zKSB7XG4gICAgZW52LnNldChfLm9taXQob3B0aW9ucywgJ2VsJykpO1xufVxuXG52YXIgQXNzaWdubWVudCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgc2V0RW52aXJvbm1lbnQob3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplKG9wdGlvbnMpO1xufTtcblxuQXNzaWdubWVudC5wcm90b3R5cGUgPSB7XG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLmVsID0gdHlwZW9mIG9wdGlvbnMuZWwgPT09ICdzdHJpbmcnID8gJChvcHRpb25zLmVsKVswXSA6IG9wdGlvbnMuZWw7XG4gICAgICAgIHRoaXMuJGVsID0gJCh0aGlzLmVsKTtcbiAgICAgICAgdGhpcy4kID0gXy5wYXJ0aWFsUmlnaHQoJCwgdGhpcy5lbCk7XG5cbiAgICAgICAgdGhpcy51c2VycyA9IG5ldyBVc2Vyc0NvbGxlY3Rpb24oKTtcbiAgICAgICAgdGhpcy53b3JsZHMgPSBuZXcgV29ybGRzQ29sbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnByb2plY3QgPSBuZXcgUHJvamVjdE1vZGVsKCk7XG5cbiAgICAgICAgXy5iaW5kQWxsKHRoaXMsIFsncmVuZGVyJywgJ3JlbmRlclRhYmxlJywgJ3RvZ2dsZUNvbnRyb2xscycsICdzYXZlRWRpdCcsICdzZWxlY3RBbGwnLCAndXNhc3NpZ25TZWxlY3RlZCcsICdfc2hvd1VwZGF0aW5nJywgJ19oaWRlVXBkYXRpbmcnLCAnYXV0b0Fzc2lnbkFsbCcsICdtYWtlVXNlckluYWN0aXZlJ10pO1xuXG4gICAgICAgIHRoaXMuYmluZEV2ZW50cygpO1xuICAgIH0sXG5cbiAgICBiaW5kRXZlbnRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9uKCd1cGRhdGUnLCAndHInLCB0aGlzLnNhdmVFZGl0KTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2lucHV0OmNoZWNrYm94Om5vdCgjc2VsZWN0LWFsbCknLCB0aGlzLnRvZ2dsZUNvbnRyb2xscyk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICcjc2VsZWN0LWFsbCcsIHRoaXMuc2VsZWN0QWxsKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy51bmFzc2lnbi11c2VyJywgdGhpcy51c2Fzc2lnblNlbGVjdGVkKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy5hdXRvLWFzc2lnbi1hbGwnLCB0aGlzLmF1dG9Bc3NpZ25BbGwpO1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnLm1ha2UtdXNlci1pbmFjdGl2ZScsIHRoaXMubWFrZVVzZXJJbmFjdGl2ZSk7XG4gICAgfSxcblxuICAgIGxvYWQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB2YXIgam9pbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLnNldFVzZXJzQ29sbGVjdGlvbih0aGlzLnVzZXJzKTtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLmpvaW5Vc2VycygpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHJldHVybiAkLndoZW4oXG4gICAgICAgICAgICB0aGlzLndvcmxkcy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy51c2Vycy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy5wcm9qZWN0LmZldGNoKClcbiAgICAgICAgKS50aGVuKGpvaW4pO1xuXG4gICAgfSxcblxuICAgIHNhdmVFZGl0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMud29ybGRzLmZldGNoKClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ29udHJvbHMoKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGF1dG9Bc3NpZ25BbGw6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG4gICAgICAgIHZhciBtYXhVc2VycyA9ICt0aGlzLiQoJyNtYXgtdXNlcnMnKS52YWwoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMud29ybGRzLmF1dG9Bc3NpZ25BbGwoeyBtYXhVc2VyczogbWF4VXNlcnMgfSlcbiAgICAgICAgICAgIC5kb25lKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC5mYWlsKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9LFxuXG4gICAgZ2V0U2VsZWN0ZWRJZHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuJCgndGJvZHkgOmNoZWNrYm94OmNoZWNrZWQnKS5tYXAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICQodGhpcykuZGF0YSgnaWQnKTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGZpbmRSb3dWaWV3czogZnVuY3Rpb24gKGlkcykge1xuICAgICAgICByZXR1cm4gXy5tYXAoaWRzLCBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJvd1ZpZXdzW2lkXTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfSxcblxuICAgIHVuYXNzaWduVXNlcnM6IGZ1bmN0aW9uIChpZHMpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIGZvciBub3cgd2UgbmVlZCB0byBzZXF1ZW5jZSB0aGUgY2FsbHMgdG8gdW5hc3NpZ24gdXNlcnMgZnJvbSB3b3JsZHNcbiAgICAgICAgdmFyIHF1ZXVlID0gbmV3IEFqYXhRdWV1ZSgpO1xuXG4gICAgICAgIF8uZWFjaChpZHMsIGZ1bmN0aW9uICh1c2VySWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyID0gdGhpcy51c2Vycy5nZXRCeUlkKHVzZXJJZCk7XG4gICAgICAgICAgICB1c2VyLnNldCgnd29ybGQnLCAnJyk7XG4gICAgICAgICAgICB1c2VyLnNldCgncm9sZScsICcnKTtcbiAgICAgICAgICAgIHF1ZXVlLmFkZChfLnBhcnRpYWwoXy5iaW5kKHRoaXMud29ybGRzLnVwZGF0ZVVzZXIsIHRoaXMud29ybGRzKSwgdXNlcikpO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIHVzYXNzaWduU2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICB2YXIgaWRzID0gdGhpcy5nZXRTZWxlY3RlZElkcygpO1xuXG4gICAgICAgIHZhciBkb25lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy53b3JsZHMuZmV0Y2goKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9oaWRlVXBkYXRpbmcoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudW5hc3NpZ25Vc2VycyhpZHMpLnRoZW4oZG9uZSk7XG4gICAgfSxcblxuICAgIG1ha2VVc2VySW5hY3RpdmU6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdmFyIGlkcyA9IHRoaXMuZ2V0U2VsZWN0ZWRJZHMoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIG1ha2VVc2Vyc0luYWN0aXZlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJvd3MgPSB0aGlzLmZpbmRSb3dWaWV3cyhpZHMpO1xuICAgICAgICAgICAgLy8gZm9yIG5vdyB3ZSBuZWVkIHRvIHNlcXVlbmNlIHRoZSBjYWxscyB0byBwYXRjaCB0aGUgdXNlcnNcbiAgICAgICAgICAgIC8vIHNpbmNlIHRoZSBBUEkgY2FuIG9ubHkgb3BlcmF0ZSBvbiBvbmUgY2FsbCBwZXIgZ3JvdXAgYXQgYSB0aW1lXG4gICAgICAgICAgICB2YXIgcXVldWUgPSBuZXcgQWpheFF1ZXVlKCk7XG4gICAgICAgICAgICBfLmVhY2gocm93cywgZnVuY3Rpb24gKHZpZXcpIHtcbiAgICAgICAgICAgICAgICB2YXIgdXNlciA9IHZpZXcubW9kZWw7XG4gICAgICAgICAgICAgICAgcXVldWUuYWRkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZpZXcubWFrZUluYWN0aXZlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZXcucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gdGhpcy51bmFzc2lnblVzZXJzKGlkcylcbiAgICAgICAgICAgIC50aGVuKG1ha2VVc2Vyc0luYWN0aXZlKTtcblxuXG4gICAgfSxcblxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiQoJ3RhYmxlIHRib2R5JykuZW1wdHkoKTtcbiAgICAgICAgdGhpcy5yZW5kZXJUYWJsZSgpO1xuICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgIH0sXG5cbiAgICByZW5kZXJUYWJsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJvd1ZpZXdzID0ge307XG4gICAgICAgIHZhciByb3dzID0gW107XG4gICAgICAgIHRoaXMudXNlcnMuZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgQXNzaWduZW1udFJvdyh7IG1vZGVsOiB1LCB3b3JsZHM6IHRoaXMud29ybGRzLCBwcm9qZWN0OiB0aGlzLnByb2plY3QgfSk7XG4gICAgICAgICAgICB0aGlzLnJvd1ZpZXdzW3UuZ2V0KCdpZCcpXSA9IHZpZXc7XG4gICAgICAgICAgICByb3dzLnB1c2godmlldy5yZW5kZXIoKS5lbCk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHRoaXMuJCgndGFibGUgdGJvZHknKS5hcHBlbmQocm93cyk7XG4gICAgfSxcblxuXG4gICAgdXBkYXRlQ29udHJvbHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9sc0ZvclNlbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnVwZGF0ZUF1dG9Bc3NpZ25CdXR0b24oKTtcbiAgICAgICAgdGhpcy51cGRhdGVTdGF0dXMoKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlU3RhdHVzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbmNvbHBsZXRlV29ybGRzID0gdGhpcy53b3JsZHMuZ2V0SW5jb21wbGV0ZVdvcmxkc0NvdW50KCk7XG4gICAgICAgIHZhciB1bmFzc2lnbmVkVXNlcnMgPSB0aGlzLnVzZXJzLmdldFVuYXNzaWduZWRVc2Vyc0NvdW50KCk7XG4gICAgICAgIHZhciB0b3RhbFdvcmxkcyA9IHRoaXMud29ybGRzLnNpemUoKTtcblxuICAgICAgICB2YXIgdXNlcnNUZXh0ID0gdW5hc3NpZ25lZFVzZXJzID8gdW5hc3NpZ25lZFVzZXJzID09PSAxID8gJzEgdXNlciBuZWVkcyBhc3NpZ25tZW50LicgOiB1bmFzc2lnbmVkVXNlcnMgKyAnIHVzZXJzIG5lZWQgYXNzaWdubWVudC4nIDogJ0FsbCB1c2VycyBoYXZlIGJlZW4gYXNzaWduZWQuJztcbiAgICAgICAgdmFyIHdvcmxkc1RleHQgPSAhdG90YWxXb3JsZHMgPyAnTm8gd29ybGRzIGhhdmUgYmVlbiBjcmVhdGVkLicgOiAhaW5jb2xwbGV0ZVdvcmxkcyA/ICdBbGwgd29ybGRzIGFyZSBjb21wbGV0ZS4nIDogaW5jb2xwbGV0ZVdvcmxkcyA9PT0gMSA/ICcxIGluY29tcGxldGUgd29ybGQgbmVlZHMgYXR0ZW50aW9uLicgOiBpbmNvbHBsZXRlV29ybGRzICsgJyBpbmNvbXBsZXRlIHdvcmxkcyBuZWVkIGF0dGVudGlvbi4nO1xuXG4gICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cyAudGV4dCcpLnRleHQodXNlcnNUZXh0KTtcbiAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cyAudGV4dCcpLnRleHQod29ybGRzVGV4dCk7XG5cbiAgICAgICAgaWYgKHVuYXNzaWduZWRVc2Vycykge1xuICAgICAgICAgICAgdGhpcy4kKCcjdXNlcnMtc3RhdHVzJykuYWRkQ2xhc3MoJ2luY29tcGxldGUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5jb2xwbGV0ZVdvcmxkcyB8fCAhdG90YWxXb3JsZHMpIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3dvcmxkcy1zdGF0dXMnKS5hZGRDbGFzcygnaW5jb21wbGV0ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLiQoJy5zdGF0dXMtd2lkZ2V0JykuYWRkQ2xhc3MoJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQ29udHJvbHNGb3JTZWxlY3Rpb246IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG51bVNlbGVjdGVkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpLmxlbmd0aDtcbiAgICAgICAgdGhpcy4kKCcuY29tcG9uZW50LmNvbnRyb2xzJylbbnVtU2VsZWN0ZWQgPyAnYWRkQ2xhc3MnIDogJ3JlbW92ZUNsYXNzJ10oJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQXV0b0Fzc2lnbkJ1dHRvbjogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIGlmICh0aGlzLnByb2plY3QuaXNEeW5hbWljQXNzaWdubWVudCgpKSB7XG4gICAgICAgICAgICB2YXIgaGFzUm9sZXMgPSB0aGlzLnByb2plY3QuaGFzUm9sZXMoKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5zaW5nbGUnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYycpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5keW5hbWljLW5vLXJvbGVzLXRleHQnKVtoYXNSb2xlcyA/ICdoaWRlJyA6ICdzaG93J10oKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpW2hhc1JvbGVzID8gJ2hpZGUnIDogJ3Nob3cnXSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLmR5bmFtaWMnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYy1uby1yb2xlcy10ZXh0JykuaGlkZSgpO1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLnNpbmdsZScpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpLnNob3coKTtcblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudXNlcnMuYWxsVXNlcnNBc3NpZ25lZCgpKSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLnJlbW92ZUNsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLmFkZENsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc2VsZWN0QWxsOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICB0aGlzLiQoJ3Rib2R5IDpjaGVja2JveCcpLnByb3AoJ2NoZWNrZWQnLCBlLnRhcmdldC5jaGVja2VkKTtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICB0b2dnbGVDb250cm9sbHM6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB0b3RhbCA9IHRoaXMuJCgndGJvZHkgOmNoZWNrYm94Jyk7XG4gICAgICAgIHZhciBjaGVja2VkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpO1xuXG4gICAgICAgIGlmICh0b3RhbC5sZW5ndGggPT09IGNoZWNrZWQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykuYXR0cignY2hlY2tlZCcsICdjaGVja2VkJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykucmVtb3ZlQXR0cignY2hlY2tlZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICBfc2hvd1VwZGF0aW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLmNzcyh7IG9wYWNpdHk6IDAuNCB9KTtcbiAgICB9LFxuXG4gICAgX2hpZGVVcGRhdGluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5jc3MoeyBvcGFjaXR5OiAxIH0pO1xuICAgIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBc3NpZ25tZW50OyIsIid1c2Ugc3RyaWN0JztcblxudmFyIEJhc2VDb2xsZWN0aW9uID0gZnVuY3Rpb24gKG1vZGVscywgb3B0aW9ucykge1xuICAgIHRoaXMuX21vZGVscyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlQ29sbGVjdGlvbi5wcm90b3R5cGUsIHtcbiAgICBpZEF0dHJpYnV0ZTogJ2lkJyxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uIChtb2RlbHMsIG9wdGlvbnMpIHtcbiAgICB9LFxuXG4gICAgY3JlYXRlOiBmdW5jdGlvbiAoYXR0ciwgb3B0aW9ucykge1xuICAgICAgICB2YXIgbSA9IG5ldyB0aGlzLm1vZGVsKGF0dHIsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnNldChtKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAobW9kZWxzLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMuX21vZGVscy5sZW5ndGggPSAwO1xuICAgICAgICB0aGlzLnNldChtb2RlbHMpO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uIChtb2RlbCkge1xuICAgICAgICBfLnJlbW92ZSh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbSA9PT0gbW9kZWw7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGRlbGV0ZSBtb2RlbC5jb2xsZWN0aW9uO1xuXG4gICAgICAgIHJldHVybiBtb2RlbDtcbiAgICB9LFxuXG4gICAgc2V0OiBmdW5jdGlvbiAobW9kZWxzKSB7XG4gICAgICAgIGlmICghbW9kZWxzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBtb2RlbHMgPSBbXS5jb25jYXQobW9kZWxzKTtcblxuICAgICAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIF8uZWFjaChtb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICBpZiAoIShtIGluc3RhbmNlb2YgdGhpcy5tb2RlbCkpIHtcbiAgICAgICAgICAgICAgICBtID0gbmV3IHRoaXMubW9kZWwobSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG0uY29sbGVjdGlvbiA9IHRoaXM7XG5cbiAgICAgICAgICAgIHRoaXMuX21vZGVscy5wdXNoKG0pO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICB0aGlzLnNvcnQuY2FsbCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gbW9kZWxzO1xuICAgIH0sXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBiLl9kYXRhW3RoaXMuaWRBdHRyaWJ1dGVdIC0gYS5fZGF0YVt0aGlzLmlkQXR0cmlidXRlXTtcbiAgICB9LFxuXG4gICAgc29ydDogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLl9tb2RlbHMgPSB0aGlzLl9tb2RlbHMuc29ydCh0aGlzLnNvcnRGbi5iaW5kKHRoaXMpKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzO1xuICAgIH0sXG5cbiAgICBnZXRCeUlkOiBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgcmV0dXJuIF8uZmluZCh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbS5nZXQodGhpcy5pZEF0dHJpYnV0ZSkgPT09IGlkO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgZWFjaDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uZWFjaCh0aGlzLl9tb2RlbHMsIGNiLCBjdHggfHwgdGhpcyk7XG4gICAgfSxcblxuICAgIGFsbDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uYWxsKHRoaXMuX21vZGVscywgY2IsIGN0eCB8fCB0aGlzKTtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBfLmludm9rZSh0aGlzLl9tb2RlbHMsICd0b0pTT04nKTtcbiAgICB9LFxuXG4gICAgZmluZDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbmQodGhpcy5fbW9kZWxzLCBmbik7XG4gICAgfSxcblxuICAgIGZpbHRlcjogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbHRlcih0aGlzLl9tb2RlbHMsIGZuKTtcbiAgICB9LFxuXG4gICAgc2l6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgbWFwOiBmdW5jdGlvbiAoZm4sIGN0eCkge1xuICAgICAgICByZXR1cm4gXy5tYXAodGhpcy5fbW9kZWxzLCBmdW5jdGlvbiAobW9kZWwpIHtcbiAgICAgICAgICAgIHJldHVybiBmbi5jYWxsKGN0eCwgbW9kZWwudG9KU09OKCkpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgcGx1Y2s6IGZ1bmN0aW9uIChmaWVsZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBtW2ZpZWxkXTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlQ29sbGVjdGlvbjsiLCIndXNlIHN0cmljdCc7XG5cblxudmFyIEJhc2VNb2RlbCA9IGZ1bmN0aW9uIChhdHRyLCBvcHRpb25zKSB7XG4gICAgYXR0ciA9IF8uZGVmYXVsdHMoe30sIGF0dHIsIF8ucmVzdWx0KHRoaXMsICdkZWZhdWx0cycpKTtcbiAgICB0aGlzLl9kYXRhID0ge307XG4gICAgdGhpcy5zZXQoYXR0ciwgb3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlTW9kZWwucHJvdG90eXBlLCB7XG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKGF0dHIsIG9wdGlvbnMpIHtcblxuICAgIH0sXG5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbCwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChrZXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWw7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBfLmV4dGVuZCh0aGlzLl9kYXRhLCBhdHRycyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGdldDogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YVtrZXldO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jb2xsZWN0aW9uLnJlbW92ZSh0aGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICB0b0pTT046IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGE7XG4gICAgfSxcblxuICAgIHBpY2s6IGZ1bmN0aW9uIChrZXlzKSB7XG4gICAgICAgIHJldHVybiBfLnBpY2sodGhpcy5fZGF0YSwga2V5cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlTW9kZWw7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZW52ID0ge1xuICAgIGFjY291bnQ6ICcnLFxuICAgIHByb2plY3Q6ICcnLFxuICAgIGdyb3VwOiAnJyxcbiAgICBncm91cElkOiAnJyxcbiAgICB0b2tlbjogJycsXG4gICAgc2VydmVyOiB7XG4gICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgcHJvdG9jb2w6ICdodHRwcydcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBzZXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGVudiA9IF8ubWVyZ2UoZW52LCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBlbnY7XG4gICAgfVxufTsiLCIoZnVuY3Rpb24gKCkge1xuICAgICd1c2Ugc3RyaWN0JztcbiAgICB2YXIgQXBwID0gcmVxdWlyZSgnLi9hc3NpZ25tZW50LmpzJyk7XG5cbiAgICB3aW5kb3cuZm9yaW8gPSB3aW5kb3cuZm9yaW8gfHwge307XG4gICAgd2luZG93LmZvcmlvLk11bHRpcGxheWVyQXNzaWdubWVudENvbXBvbmVudCA9IEFwcDtcbn0pKCk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBzZXJ2aWNlTG9jYXRvciA9IHJlcXVpcmUoJy4vc2VydmljZS1sb2NhdG9yJyk7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG4vLyB2YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBpc0R5bmFtaWNBc3NpZ25tZW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldCgnd29ybGRzJykgPT09ICdkeW5hbWljJztcbiAgICB9LFxuXG4gICAgaGFzUm9sZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJvbGVzID0gdGhpcy5nZXQoJ3JvbGVzJyk7XG4gICAgICAgIHJldHVybiByb2xlcyAmJiAhIXJvbGVzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGFwaSA9IHNlcnZpY2VMb2NhdG9yLndvcmxkQXBpKCk7XG5cbiAgICAgICAgcmV0dXJuIGFwaS5nZXRQcm9qZWN0U2V0dGluZ3MoKS50aGVuKGZ1bmN0aW9uIChzZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5zZXQoc2V0dGluZ3MpO1xuICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cbn0pOyIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVudiA9IHJlcXVpcmUoJy4vZGVmYXVsdHMuanMnKTtcblxudmFyIGNhY2hlID0ge307XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHdvcmxkQXBpOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghY2FjaGUud29ybGRBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLndvcmxkQXBpID0gbmV3IEYuc2VydmljZS5Xb3JsZChlbnYuZ2V0KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLndvcmxkQXBpO1xuICAgIH0sXG5cbiAgICBtZW1iZXJBcGk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFjYWNoZS5tZW1iZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLm1lbWJlckFwaSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKF8ucGljayhlbnYuZ2V0KCksIFsnZ3JvdXBJZCcsICdzZXJ2ZXInXSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLm1lbWJlckFwaTtcbiAgICB9LFxuXG4gICAgdXNlckFwaTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIWNhY2hlLnVzZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLnVzZXJBcGkgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoXy5waWNrKGVudi5nZXQoKSwgWydhY2NvdW50JywgJ3NlcnZlciddKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2FjaGUudXNlckFwaTtcbiAgICB9XG59OyIsImV4cG9ydHNbXCJlZGl0LXVzZXItcm93XCJdID0gZnVuY3Rpb24ob2JqKSB7XG5vYmogfHwgKG9iaiA9IHt9KTtcbnZhciBfX3QsIF9fcCA9ICcnLCBfX2UgPSBfLmVzY2FwZSwgX19qID0gQXJyYXkucHJvdG90eXBlLmpvaW47XG5mdW5jdGlvbiBwcmludCgpIHsgX19wICs9IF9fai5jYWxsKGFyZ3VtZW50cywgJycpIH1cbndpdGggKG9iaikge1xuX19wICs9ICc8dGQ+PGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGNsYXNzPVwic2VsZWN0XCIgZGF0YS1pZD1cIicgK1xuKChfX3QgPSAoIGlkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+PC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cIndvcmxkc1wiIGNsYXNzPVwiZm9ybS1jb250cm9sXCIgZGF0YS1maWVsZD1cIndvcmxkXCI+XFxuXFxuICAgICc7XG4gXy5lYWNoKHdvcmxkcywgZnVuY3Rpb24gKHcpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHcgPT09IHdvcmxkID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIicgK1xuKChfX3QgPSAoIG5ld1dvcmxkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiIGNsYXNzPVwibmV3LXdvcmxkLXRleHRcIj48aT4nICtcbigoX190ID0gKCBuZXdXb3JsZCApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbicgLSBOZXcgLTwvaT48L29wdGlvbj5cXG4gICAgPC9zZWxlY3Q+XFxuPC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cInJvbGVzXCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBkYXRhLWZpZWxkPVwicm9sZVwiPlxcbiAgICAnO1xuIF8uZWFjaChyb2xlcywgZnVuY3Rpb24gKHIpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHIgPT09IHJvbGUgPyAnc2VsZWN0ZWQnIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPicgK1xuKChfX3QgPSAoIHIgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC9vcHRpb24+XFxuICAgICc7XG4gfSk7IDtcbl9fcCArPSAnXFxuXFxuICAgICc7XG4gXy5lYWNoKG9wdGlvbmFsUm9sZXMsIGZ1bmN0aW9uIChyKSB7IDtcbl9fcCArPSAnXFxuICAgICAgICA8b3B0aW9uIHZhbHVlPVwiJyArXG4oKF9fdCA9ICggciApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbidcIiAnICtcbigoX190ID0gKCByID09PSByb2xlID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJyA8aT4oT3B0aW9uYWwpPC9pPjwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICA8L3NlbGVjdD5cXG48L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi10b29scyBidG4tc2F2ZSBzYXZlXCI+U2F2ZTwvYnV0dG9uPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi10b29scyBidG4tY2FuY2VsIGNhbmNlbFwiPkNhbmNlbDwvYnV0dG9uPlxcbjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTtcbmV4cG9ydHNbXCJ1c2VyLXJvd1wiXSA9IGZ1bmN0aW9uKG9iaikge1xub2JqIHx8IChvYmogPSB7fSk7XG52YXIgX190LCBfX3AgPSAnJywgX19lID0gXy5lc2NhcGU7XG53aXRoIChvYmopIHtcbl9fcCArPSAnPHRkPjxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cInNlbGVjdFwiIGRhdGEtaWQ9XCInICtcbigoX190ID0gKCBpZCkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggIWlzV29ybGRDb21wbGV0ZSA/ICc8ZW0gY2xhc3M9XCJmLWljb24gZi13YXJuaW5nXCI+PC9lbT4nIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggd29ybGQgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggcm9sZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPjxidXR0b24gY2xhc3M9XCJidG4gZWRpdCBidG4tZWRpdCBidG4tdG9vbHMgYXV0by1oaWRlXCI+RWRpdDwvYnV0dG9uPjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBkZWZhdWx0czoge1xuICAgICAgICB3b3JsZDogJycsXG4gICAgICAgIHJvbGU6ICcnLFxuICAgICAgICBhY3RpdmU6IHRydWUsXG4gICAgICAgIGlzV29ybGRDb21wbGV0ZTogdHJ1ZSxcbiAgICAgICAgZmlyc3ROYW1lOiAnJyxcbiAgICAgICAgbGFzdE5hbWU6ICcnXG4gICAgfSxcblxuICAgIG1ha2VBY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gbWVtYmVyQXBpLm1ha2VVc2VyQWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBtYWtlSW5hY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBmYWxzZSk7XG5cbiAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5tYWtlVXNlckluYWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cblxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcblxudmFyIE1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcblxuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBtb2RlbDogTW9kZWwsXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHZhciBhdyA9IGEuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBidyA9IGIuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIGlmIChhdyAhPT0gYncpIHtcbiAgICAgICAgICAgIHJldHVybiBhdyA8IGJ3ID8gLTEgOiAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGIuZ2V0KCd1c2VyTmFtZScpID4gYS5nZXQoJ3VzZXJOYW1lJykgPyAtMSA6IDE7XG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJC5hamF4U2V0dXAoe1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIGVudi5nZXQoKS50b2tlblxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgYWxsVXNlcnNBc3NpZ25lZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hbGwoZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiAhIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0VW5hc3NpZ25lZFVzZXJzQ291bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmlsdGVyKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICByZXR1cm4gIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KS5sZW5ndGg7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBncm91cElkID0gZW52LmdldCgpLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGdldEdyb3VwVXNlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbWVtYmVyQXBpID0gc2VydmljZUxvY2F0b3IubWVtYmVyQXBpKCk7XG4gICAgICAgICAgICB2YXIgdXNlckFwaSA9IHNlcnZpY2VMb2NhdG9yLnVzZXJBcGkoKTtcblxuICAgICAgICAgICAgdmFyIGxvYWRHcm91cE1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5nZXRHcm91cERldGFpbHMoKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBsb2FkVXNlcnNJbmZvID0gZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vbkZhY0FuZEFjdGl2ZSA9IGZ1bmN0aW9uICh1KSB7IHJldHVybiB1LmFjdGl2ZSAmJiB1LnJvbGUgIT09ICdmYWNpbGl0YXRvcic7IH07XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJzID0gXy5wbHVjayhfLmZpbHRlcihncm91cC5tZW1iZXJzLCBub25GYWNBbmRBY3RpdmUpLCAndXNlcklkJyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVzZXJBcGkuZ2V0KHsgaWQ6IHVzZXJzIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGxvYWRHcm91cE1lbWJlcnMoKVxuICAgICAgICAgICAgICAgIC50aGVuKGxvYWRVc2Vyc0luZm8pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgZ2V0R3JvdXBVc2VycygpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAodXNlcnMpIHtcbiAgICAgICAgICAgICAgICB1c2VycyA9IF8ubWFwKHVzZXJzLCBmdW5jdGlvbiAodSkgeyByZXR1cm4gXy5leHRlbmQodSwgeyBncm91cElkOiBncm91cElkIH0pOyB9KTtcbiAgICAgICAgICAgICAgICBfdGhpcy5zZXQodXNlcnMpO1xuICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHVzZXJzLCBfdGhpcyk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9XG5cbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBkZWZhdWx0czoge1xuICAgICAgICB1c2VyczogbnVsbCxcbiAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX19zdXBlci5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgdGhpcy5fZGF0YS51c2VycyA9IHRoaXMuX2RhdGEudXNlcnMgfHwgW107XG5cbiAgICAgICAgdGhpcy5fd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuXG4gICAgICAgIHZhciBpZCA9IHRoaXMuZ2V0KCdpZCcpO1xuICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgYWRkVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIHVzZXJzLnB1c2godXNlcik7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuc2F2ZSgpO1xuICAgIH0sXG5cbiAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlcikge1xuICAgICAgICB2YXIgaWQgPSB0aGlzLmdldCgnaWQnKTtcbiAgICAgICAgdmFyIGNoZWNrV29ybGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuZ2V0KCd1c2VycycpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSkuZGVsZXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICBfLnJlbW92ZSh0aGlzLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiB1LmdldCgnaWQnKSA9PT0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl93b3JsZEFwaVxuICAgICAgICAgICAgLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSlcbiAgICAgICAgICAgIC5yZW1vdmVVc2VyKHsgdXNlcklkOiB1c2VyLmdldCgnaWQnKSB9KVxuICAgICAgICAgICAgLnRoZW4oY2hlY2tXb3JsZCk7XG4gICAgfSxcblxuICAgIHNhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIG1hcFVzZXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIF8ubWFwKHRoaXMuZ2V0KCd1c2VycycpLCBmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgICAgIHZhciByZXMgPSB7IHVzZXJJZDogdS5nZXQoJ2lkJykgfTtcbiAgICAgICAgICAgICAgICB2YXIgcm9sZSA9IHUuZ2V0KCdyb2xlJyk7XG5cbiAgICAgICAgICAgICAgICBpZiAocm9sZSkge1xuICAgICAgICAgICAgICAgICAgICByZXMucm9sZSA9IHJvbGU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIGNyZWF0ZVdvcmxkID0gXy5wYXJ0aWFsKHRoaXMuX3dvcmxkQXBpLmNyZWF0ZSwgdGhpcy5waWNrKFsnbW9kZWwnLCAnbmFtZScsICdtaW5Vc2VycyddKSk7XG4gICAgICAgIHZhciBhZGRVc2VycyA9IF8ucGFydGlhbChfdGhpcy5fd29ybGRBcGkuYWRkVXNlcnMsIG1hcFVzZXJzKCksIHsgZmlsdGVyOiBfdGhpcy5nZXQoJ2lkJykgfSk7XG4gICAgICAgIHZhciBzYXZlZFVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIGlmICh0aGlzLmlzTmV3KCkpIHtcbiAgICAgICAgICAgIC8vIHdlIG5lZWQgdG8gY3JlYXRlIHRoZSB3b3JsZCBpbiB0aGUgQVBJIGFuZCB0aGVuIGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVXb3JsZCgpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNldCh3b3JsZCk7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLl93b3JsZEFwaS51cGRhdGVDb25maWcoeyBmaWx0ZXI6IHdvcmxkLmlkIH0pO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oYWRkVXNlcnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHVzZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHNpbmNlIHdlIHJlLXNldCB0aGUgd29ybGQsIHJlLXNldCB0aGUgdXNlcnNcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuc2V0KCd1c2VycycsIHNhdmVkVXNlcnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gdGhlIHdvcmxkIGlzIGFscmVhZHkgY3JlYXRlZCBqdXN0IGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBhZGRVc2VycygpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGlzTmV3OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5nZXQoJ2xhc3RNb2RpZmllZCcpO1xuICAgIH1cblxufSk7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgTW9kZWwgPSByZXF1aXJlKCcuL3dvcmxkLW1vZGVsJyk7XG52YXIgVXNlck1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG52YXIgZG9uZUZuID0gZnVuY3Rpb24gKGR0ZCwgYWZ0ZXIpIHtcbiAgICByZXR1cm4gXy5hZnRlcihhZnRlciwgZHRkLnJlc29sdmUpO1xufTtcblxudmFyIHdvcmxkQXBpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgbW9kZWw6IE1vZGVsLFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBfX3N1cGVyLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuICAgIH0sXG5cbiAgICBhdXRvQXNzaWduQWxsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gd29ybGRBcGkuYXV0b0Fzc2lnbihvcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzZXQodGhpcy5wYXJzZSh3b3JsZHMpKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGdldEluY29tcGxldGVXb3JsZHNDb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24gKHcpIHtcbiAgICAgICAgICAgIHJldHVybiAhdy5nZXQoJ2NvbXBsZXRlJyk7XG4gICAgICAgIH0pLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgdXBkYXRlVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHdvcmxkTmFtZSA9IHVzZXIuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgcHJldldvcmxkID0gdGhpcy5nZXRXb3JsZEJ5VXNlcih1c2VyKTtcbiAgICAgICAgdmFyIGN1cldvcmxkID0gdGhpcy5nZXRPckNyZWF0ZVdvcmxkKHdvcmxkTmFtZSk7XG4gICAgICAgIHZhciBkb25lID0gZG9uZUZuKGR0ZCwgMSk7XG5cbiAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUncyBhbnl0aGluZyB0byBkb1xuICAgICAgICBpZiAoIXByZXZXb3JsZCAmJiAhY3VyV29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiBkdGQucmVzb2x2ZSgpLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwcmV2V29ybGQpIHtcbiAgICAgICAgICAgIHByZXZXb3JsZC5yZW1vdmVVc2VyKHVzZXIpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY3VyV29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjdXJXb3JsZC5hZGRVc2VyKHVzZXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAudGhlbihkb25lKTtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJXb3JsZCkge1xuICAgICAgICAgICAgY3VyV29ybGQuYWRkVXNlcih1c2VyKVxuICAgICAgICAgICAgICAgIC50aGVuKGRvbmUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldE9yQ3JlYXRlV29ybGQ6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgaWYgKCF3b3JsZE5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB3b3JsZCA9IHRoaXMuZ2V0V29yZEJ5TmFtZSh3b3JsZE5hbWUpO1xuXG4gICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgIHdvcmxkID0gdGhpcy5jcmVhdGUoeyBuYW1lOiB3b3JsZE5hbWUgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gd29ybGQ7XG4gICAgfSxcblxuICAgIGdldFdvcmRCeU5hbWU6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmluZChmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiB3b3JsZC5nZXQoJ25hbWUnKSA9PT0gd29ybGROYW1lO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGRCeVVzZXI6IGZ1bmN0aW9uICh1c2VyKSB7XG4gICAgICAgIGlmICghdXNlci5nZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZ2V0V29ybGRCeVVzZXIgZXhwZWN0ZXMgYSBtb2RlbCAoJyArIHVzZXIgKyAnKScpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGlkID0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFdvcmxkQnlVc2VySWQoaWQpO1xuICAgIH0sXG5cbiAgICBnZXRXb3JsZEJ5VXNlcklkOiBmdW5jdGlvbiAodXNlcklkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZpbmQoZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICByZXR1cm4gXy5maW5kKHdvcmxkLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdS5nZXQoJ2lkJykgPT09IHVzZXJJZDtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGROYW1lczogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wbHVjaygnbmFtZScpO1xuICAgIH0sXG5cbiAgICBnZXROZXh0V29ybGROYW1lOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBwYWQgPSBmdW5jdGlvbiAobnVtLCBwbGFjZXMpIHtcbiAgICAgICAgICAgIHZhciB6ZXJvcyA9ICcwMDAwMDAwMDAwMDAwMDAwMDAnO1xuICAgICAgICAgICAgdmFyIGRpZ2l0cyA9IG51bS50b1N0cmluZygpLmxlbmd0aDtcbiAgICAgICAgICAgIHZhciBuZWVkZWQgPSBwbGFjZXMgLSBkaWdpdHM7XG4gICAgICAgICAgICByZXR1cm4gemVyb3Muc3Vic3RyKDAsIG5lZWRlZCkgKyBudW07XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHdvcmxkcyA9IHRoaXMuZ2V0V29ybGROYW1lcygpO1xuXG4gICAgICAgIGlmICghd29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuICdXb3JsZDAwMSc7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcHJvcGVyTmFtZXMgPSBfLmZpbHRlcih3b3JsZHMsIGZ1bmN0aW9uICh3KSB7IHJldHVybiAvV29ybGRcXGRcXGRcXGQvLnRlc3Qodyk7IH0pLnNvcnQoKTtcbiAgICAgICAgdmFyIGxhc3RXb3JsZCA9IHByb3Blck5hbWVzW3Byb3Blck5hbWVzLmxlbmd0aCAtIDFdO1xuICAgICAgICB2YXIgbnVtV29ybGQgPSArbGFzdFdvcmxkLm1hdGNoKC9Xb3JsZChcXGRcXGRcXGQpLylbMV07XG4gICAgICAgIHJldHVybiAnV29ybGQnICsgcGFkKG51bVdvcmxkICsgMSwgMyk7XG4gICAgfSxcblxuICAgIHNldFVzZXJzQ29sbGVjdGlvbjogZnVuY3Rpb24gKHVzZXJzQ29sbGVjdGlvbikge1xuICAgICAgICB0aGlzLnVzZXJzQ29sbGVjdGlvbiA9IHVzZXJzQ29sbGVjdGlvbjtcbiAgICB9LFxuXG4gICAgam9pblVzZXJzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1c2Vyc0hhc2ggPSB7fTtcbiAgICAgICAgdmFyIHVzZXJzQ29sbGVjdGlvbiA9IHRoaXMudXNlcnNDb2xsZWN0aW9uO1xuICAgICAgICB1c2Vyc0NvbGxlY3Rpb24uZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdS5zZXQoeyBpc1dvcmxkQ29tcGxldGU6IHRydWUgfSk7XG4gICAgICAgICAgICByZXR1cm4gKHVzZXJzSGFzaFt1LmdldCgnaWQnKV0gPSB1KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5lYWNoKGZ1bmN0aW9uICh3LCBpKSB7XG4gICAgICAgICAgICB2YXIgbmFtZSA9IHcuZ2V0KCduYW1lJyk7XG4gICAgICAgICAgICB2YXIgaXNDb21wbGV0ZSA9IHcuZ2V0KCdjb21wbGV0ZScpO1xuICAgICAgICAgICAgdy5zZXQoeyBpbmRleDogaSwgbmFtZTogbmFtZSB8fCAoaSArIDEpICsgJycgfSk7XG4gICAgICAgICAgICBfLmVhY2gody5nZXQoJ3VzZXJzJyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgaWYgKHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldKSB7XG4gICAgICAgICAgICAgICAgICAgIHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldLnNldCh7IHdvcmxkOiBuYW1lLCByb2xlOiB1LmdldCgncm9sZScpLCBpc1dvcmxkQ29tcGxldGU6IGlzQ29tcGxldGUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHVzZXJzQ29sbGVjdGlvbi5zb3J0KCk7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB3b3JsZEFwaS5saXN0KClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc2V0KHRoaXMucGFyc2Uod29ybGRzKSk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBwYXJzZTogZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICBpZiAod29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgd29ybGRzID0gXy5tYXAod29ybGRzLCBmdW5jdGlvbiAodykge1xuICAgICAgICAgICAgICAgIHZhciB1c2VycyA9IF8ubWFwKHcudXNlcnMsIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGluIHRoZSB3b3JsZCBhcGkgdXNlcnMgSWRzIGNvbWVzIGFzIHVzZXJJZFxuICAgICAgICAgICAgICAgICAgICAvLyBtYWtlIHN1cmUgd2UgYWRkIGl0IGFzIGlkIHNvIHdlIGNhbiB1c2UgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIHNhbWUgY29kZSB0byBhY2Nlc3MgbW9kZWxzIHRoYXQgY29tZSBmcm9tIHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyBtZW1iZXIvbG9jYWwgYXBpIGFzIHdpdGggdGhlIHdvcmxkIGFwaVxuICAgICAgICAgICAgICAgICAgICB1LmlkID0gdS51c2VySWQ7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVXNlck1vZGVsKHUpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgdy51c2VycyA9IHVzZXJzO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHc7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB3b3JsZHM7XG4gICAgfVxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuKiBVdGlsaXR5IGNsYXNzIHRvIG1ha2UgYWpheCBjYWxscyBzZXF1ZW5jaWFsXG4qL1xuZnVuY3Rpb24gQWpheFF1ZXVlICgpIHtcbiAgICB0aGlzLnF1ZXVlID0gW107XG59XG5cbiQuZXh0ZW5kKEFqYXhRdWV1ZS5wcm90b3R5cGUsIHtcbiAgICBhZGQ6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICByZXR1cm4gdGhpcy5xdWV1ZS5wdXNoKGZuKTtcbiAgICB9LFxuXG4gICAgZXhlY3V0ZTogZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgY29udGV4dCA9IGNvbnRleHQgfHwgdGhpcztcblxuICAgICAgICBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgICAgICAgaWYgKF90aGlzLnF1ZXVlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBmbiA9IF90aGlzLnF1ZXVlLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgICAgICBmbi5jYWxsKGNvbnRleHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKG5leHQpXG4gICAgICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbmV4dCgpO1xuXG4gICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQWpheFF1ZXVlOyIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiJdfQ== diff --git a/src/managers/auth-manager.js b/src/managers/auth-manager.js index 5aff931c..c12c0e45 100644 --- a/src/managers/auth-manager.js +++ b/src/managers/auth-manager.js @@ -52,7 +52,7 @@ var store; var token; var session; -function saveSession(userInfo) { +function saveSession(userInfo, store) { var serialized = JSON.stringify(userInfo); store.set(EPI_SESSION_KEY, serialized); @@ -61,7 +61,7 @@ function saveSession(userInfo) { store.set(EPI_COOKIE_KEY, userInfo.auth_token); } -function getSession() { +function getSession(store) { var session = store.get(EPI_SESSION_KEY) || '{}'; return JSON.parse(session); } @@ -78,10 +78,12 @@ function AuthManager(options) { if (this.options.project === undefined) { this.options.project = urlConfig.projectPath; } - - store = new StorageFactory(this.options.store); - session = getSession(); - token = store.get(EPI_COOKIE_KEY) || ''; + if (this.options.store.root === undefined) { + this.options.store.root = '/app/' + this.options.account + '/' + this.options.project; + } + this.store = new StorageFactory(this.options.store); + session = getSession(this.store); + token = this.store.get(EPI_COOKIE_KEY) || ''; //jshint camelcase: false //jscs:disable this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token }); @@ -107,9 +109,9 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * * authMgr.login({ * account: 'acme-simulations', - * project: 'supply-chain-game', + * project: 'supply-chain-game', * userName: 'enduser1', - * password: 'passw0rd' + * password: 'passw0rd' * }) * .then(function(statusObj) { * // if enduser1 belongs to exactly one group @@ -117,8 +119,8 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * // continue here * }) * .fail(function(statusObj) { - * // if enduser1 belongs to multiple groups, - * // the login() call fails + * // if enduser1 belongs to multiple groups, + * // the login() call fails * // and returns all groups of which the user is a member * for (var i=0; i < statusObj.userGroups.length; i++) { * console.log(statusObj.userGroups[i].name, statusObj.userGroups[i].groupId); @@ -127,12 +129,12 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * * **Parameters** * - * @param {Object} `options` (Optional) Overrides for configuration options. If not passed in when creating an instance of the manager (`F.manager.AuthManager()`), these options should include: + * @param {Object} `options` (Optional) Overrides for configuration options. If not passed in when creating an instance of the manager (`F.manager.AuthManager()`), these options should include: * @param {string} `options.account` The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). * @param {string} `options.userName` Email or username to use for logging in. * @param {string} `options.password` Password for specified `userName`. * @param {string} `options.project` (Optional) The **Project ID** for the project to log this user into. - * @param {string} `options.groupId` The id of the group to which `userName` belongs. Required for [end users](../../../glossary/#users) if the `project` is specified and if the end users are members of multiple [groups](../../../glossary/#groups), otherwise optional. + * @param {string} `options.groupId` The id of the group to which `userName` belongs. Required for [end users](../../../glossary/#users) if the `project` is specified and if the end users are members of multiple [groups](../../../glossary/#groups), otherwise optional. */ login: function (options) { var _this = this; @@ -165,7 +167,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { //jshint camelcase: false //jscs:disable token = response.access_token; - + var authManager = this; var userInfo = decodeToken(token); var userGroupOpts = $.extend(true, {}, adapterOptions, { success: $.noop, token: token }); _this.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts).done( function (memberInfo) { @@ -179,7 +181,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { }; // The group is not required if the user is not logging into a project if (!adapterOptions.project) { - saveSession(sessionInfo); + saveSession(sessionInfo, authManager.store); outSuccess.apply(this, [data]); $d.resolve(data); return; @@ -209,7 +211,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { 'groupName': group.name, 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator' }); - saveSession(sessionInfoWithGroup); + saveSession(sessionInfoWithGroup, authManager.store); outSuccess.apply(this, [data]); $d.resolve(data); } else { @@ -269,8 +271,8 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * **Example** * * authMgr.getToken() - * .then(function (token) { - * console.log('My token is ', token); + * .then(function (token) { + * console.log('My token is ', token); * }); * * **Parameters** @@ -298,8 +300,8 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * // get groups for current user * var sessionObj = authMgr.getCurrentUserSessionInfo(); * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token }) - * .then(function (groups) { - * for (var i=0; i < groups.length; i++) + * .then(function (groups) { + * for (var i=0; i < groups.length; i++) * { console.log(groups[i].name); } * }); * @@ -339,7 +341,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed. * - * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option. + * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option. * * **Example** * @@ -349,7 +351,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * @param {Object} `options` (Optional) Overrides for configuration options. */ getCurrentUserSessionInfo: function (options) { - return getSession(options); + return getSession(this.store, options); } }); diff --git a/src/store/cookie-store.js b/src/store/cookie-store.js index 10274980..117394a8 100644 --- a/src/store/cookie-store.js +++ b/src/store/cookie-store.js @@ -21,7 +21,7 @@ module.exports = function (config) { domain: '.forio.com' }; - var serviceOptions = $.extend({}, defaults, config); + this.serviceOptions = $.extend({}, defaults, config); var publicAPI = { // * TBD @@ -54,7 +54,7 @@ module.exports = function (config) { * cs.set({ name:'smith', age:'32' }); */ set: function (key, value, options) { - var setOptions = $.extend(true, {}, serviceOptions, options); + var setOptions = $.extend(true, {}, this.serviceOptions, options); var domain = setOptions.domain; var path = setOptions.root; @@ -91,7 +91,7 @@ module.exports = function (config) { * cs.remove('person'); */ remove: function (key, options) { - var remOptions = $.extend(true, {}, serviceOptions, options); + var remOptions = $.extend(true, {}, this.serviceOptions, options); var domain = remOptions.domain; var path = remOptions.root; diff --git a/tests/spec/test-auth-manager.js b/tests/spec/test-auth-manager.js index d96742fd..b8dc10d1 100644 --- a/tests/spec/test-auth-manager.js +++ b/tests/spec/test-auth-manager.js @@ -1,6 +1,5 @@ (function () { 'use strict'; - describe('Auth Manager', function () { var server, token; before(function () { @@ -47,5 +46,14 @@ }); // TODO: Create some test, find a way for the fake server to auto respond synchronously inside a respond callback + describe('#setting cookies', function () { + it ('creates cookie with the correct path name', function () { + var am = new F.manager.AuthManager({ + account: 'accountName', + project: 'projectName' + }); + am.store.serviceOptions.root.should.equal('/app/accountName/projectName'); + }); + }); }); }()); From 2f7b10ea85e77d13f4dce1f324db3f59c3910836 Mon Sep 17 00:00:00 2001 From: john zhang Date: Fri, 26 Feb 2016 14:05:04 -0800 Subject: [PATCH 02/14] bind login properly --- src/managers/auth-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/auth-manager.js b/src/managers/auth-manager.js index c12c0e45..99672be4 100644 --- a/src/managers/auth-manager.js +++ b/src/managers/auth-manager.js @@ -143,6 +143,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { var outSuccess = adapterOptions.success; var outError = adapterOptions.error; var groupId = adapterOptions.groupId; + var authManager = this; var decodeToken = function (token) { var encoded = token.split('.')[1]; @@ -167,7 +168,6 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { //jshint camelcase: false //jscs:disable token = response.access_token; - var authManager = this; var userInfo = decodeToken(token); var userGroupOpts = $.extend(true, {}, adapterOptions, { success: $.noop, token: token }); _this.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts).done( function (memberInfo) { From 6745e13eb4d7881c7e87af6bde6a95ab8a1cf4c2 Mon Sep 17 00:00:00 2001 From: john zhang Date: Fri, 26 Feb 2016 14:13:43 -0800 Subject: [PATCH 03/14] user proper alias for this --- src/managers/auth-manager.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/managers/auth-manager.js b/src/managers/auth-manager.js index 99672be4..5568dc15 100644 --- a/src/managers/auth-manager.js +++ b/src/managers/auth-manager.js @@ -143,7 +143,6 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { var outSuccess = adapterOptions.success; var outError = adapterOptions.error; var groupId = adapterOptions.groupId; - var authManager = this; var decodeToken = function (token) { var encoded = token.split('.')[1]; @@ -181,7 +180,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { }; // The group is not required if the user is not logging into a project if (!adapterOptions.project) { - saveSession(sessionInfo, authManager.store); + saveSession(sessionInfo, _this.store); outSuccess.apply(this, [data]); $d.resolve(data); return; @@ -211,7 +210,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { 'groupName': group.name, 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator' }); - saveSession(sessionInfoWithGroup, authManager.store); + saveSession(sessionInfoWithGroup, _this.store); outSuccess.apply(this, [data]); $d.resolve(data); } else { From 96c653ef4f755db2f3621f24c8ac1a25392190c7 Mon Sep 17 00:00:00 2001 From: john zhang Date: Fri, 26 Feb 2016 15:04:34 -0800 Subject: [PATCH 04/14] use default root unless we have both account and project information --- src/managers/auth-manager.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/managers/auth-manager.js b/src/managers/auth-manager.js index 5568dc15..fbfde1de 100644 --- a/src/managers/auth-manager.js +++ b/src/managers/auth-manager.js @@ -78,9 +78,11 @@ function AuthManager(options) { if (this.options.project === undefined) { this.options.project = urlConfig.projectPath; } - if (this.options.store.root === undefined) { + + if (this.options.store.root === undefined && this.options.account && this.options.project) { this.options.store.root = '/app/' + this.options.account + '/' + this.options.project; } + this.store = new StorageFactory(this.options.store); session = getSession(this.store); token = this.store.get(EPI_COOKIE_KEY) || ''; From feb0538db21a86989c4a16247cfd220df59df14d Mon Sep 17 00:00:00 2001 From: Molly Jones Date: Fri, 26 Feb 2016 15:08:22 -0800 Subject: [PATCH 05/14] epicenter.js dist components for epicenter-1590 branch (for testing) --- dist/components/assignment/assignment.js | 2 +- dist/epicenter.js | 51 +++++++++++++----------- dist/epicenter.min.js | 4 +- dist/epicenter.min.js.map | 2 +- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/dist/components/assignment/assignment.js b/dist/components/assignment/assignment.js index 947e5bfa..74ae582d 100644 --- a/dist/components/assignment/assignment.js +++ b/dist/components/assignment/assignment.js @@ -1231,4 +1231,4 @@ module.exports = function (base, props, staticProps) { }; },{}]},{},[6]) -//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Fzc2lnbm1lbnQtcm93LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9hc3NpZ25tZW50LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9iYXNlLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Jhc2UtbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2RlZmF1bHRzLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9pbmRleC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvcHJvamVjdC1tb2RlbC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvc2VydmljZS1sb2NhdG9yLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy90ZW1wbGF0ZXMuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXItbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXJzLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3dvcmxkLW1vZGVsLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy93b3JsZHMtY29sbGVjdGlvbi5qcyIsInNyYy91dGlsL2FqYXgtcXVldWUuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCc7XG5cbnZhciB0ZW1wbGF0ZXMgPSByZXF1aXJlKCcuL3RlbXBsYXRlcycpO1xuXG52YXIgQXNzaWdubWVudFJvdyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy4kZWwgPSAkKCc8dHI+Jyk7XG4gICAgdGhpcy5lbCA9IHRoaXMuJGVsWzBdO1xuICAgIHRoaXMuJCA9IF8ucGFydGlhbFJpZ2h0KCQsIHRoaXMuJGVsKTtcblxuICAgIHRoaXMubW9kZWwgPSBvcHRpb25zLm1vZGVsO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy53b3JsZHMgPSBvcHRpb25zLndvcmxkcztcbiAgICB0aGlzLnByb2plY3QgPSBvcHRpb25zLnByb2plY3Q7XG5cbiAgICBfLmJpbmRBbGwodGhpcywgWydzZXRFZGl0TW9kZScsICdyZW1vdmVFZGl0TW9kZScsICdzYXZlRWRpdCcsICdjYW5jZWxFZGl0JywgJ3VwZGF0ZURhdGEnXSk7XG5cbiAgICB0aGlzLmJpbmRFdmVudHMoKTtcblxufTtcblxuXy5leHRlbmQoQXNzaWdubWVudFJvdy5wcm90b3R5cGUsIHtcblxuICAgIHRlbXBsYXRlOiB0ZW1wbGF0ZXNbJ3VzZXItcm93J10sXG5cbiAgICBlZGl0VGVtcGxhdGU6IHRlbXBsYXRlc1snZWRpdC11c2VyLXJvdyddLFxuXG4gICAgYmluZEV2ZW50czogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnYnV0dG9uLmVkaXQnLCB0aGlzLnNldEVkaXRNb2RlKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2J1dHRvbi5zYXZlJywgdGhpcy5zYXZlRWRpdCk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICdidXR0b24uY2FuY2VsJywgdGhpcy5jYW5jZWxFZGl0KTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9mZignY2xpY2snLCBudWxsLCBudWxsKTtcbiAgICAgICAgLy8gdGhpcyBvbmx5IGdpdmVzIGEgZGVsYXkgdG8gcmVtb3ZlIHRoZSB0clxuICAgICAgICAvLyBhbmltYXRpb24gb2YgaGVpZ2h0IG9mIHRoZSB0ciBkb2VzIG5vdCB3b3JrXG4gICAgICAgIHRoaXMuJCgnOmNoZWNrYm94JykuYXR0cignY2hlY2tlZCcsIGZhbHNlKTtcbiAgICAgICAgdGhpcy4kZWxcbiAgICAgICAgICAgIC5jc3MoeyBvcGFjaXR5OiAwLjMgfSlcbiAgICAgICAgICAgIC5hbmltYXRlKHsgaGVpZ2h0OiAwIH0sIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMzAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIG1ha2VJbmFjdGl2ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tb2RlbC5tYWtlSW5hY3RpdmUoKTtcbiAgICB9LFxuXG4gICAgc2V0RWRpdE1vZGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5tb2RlbC5zZXQoJ2VkaXQtbW9kZScsIHRydWUpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICByZW1vdmVFZGl0TW9kZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLm1vZGVsLnNldCgnZWRpdC1tb2RlJywgZmFsc2UpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICBzYXZlRWRpdDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB0aGlzLnVwZGF0ZURhdGEoKTtcbiAgICAgICAgdGhpcy53b3JsZHNcbiAgICAgICAgICAgIC51cGRhdGVVc2VyKHRoaXMubW9kZWwpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMucmVtb3ZlRWRpdE1vZGUoKTtcbiAgICAgICAgICAgICAgICBfdGhpcy4kZWwudHJpZ2dlcigndXBkYXRlJywgX3RoaXMpO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGNhbmNlbEVkaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVFZGl0TW9kZSgpO1xuICAgIH0sXG5cbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHRlbXBsID0gdGhpcy5tb2RlbC5nZXQoJ2VkaXQtbW9kZScpID8gdGhpcy5lZGl0VGVtcGxhdGUgOiB0aGlzLnRlbXBsYXRlO1xuICAgICAgICB2YXIgdm0gPSBfLmV4dGVuZCh7XG4gICAgICAgICAgICByb2xlczogdGhpcy5wcm9qZWN0LmdldCgncm9sZXMnKSxcbiAgICAgICAgICAgIG9wdGlvbmFsUm9sZXM6IHRoaXMucHJvamVjdC5nZXQoJ29wdGlvbmFsUm9sZXMnKSxcbiAgICAgICAgICAgIHdvcmxkczogdGhpcy53b3JsZHMuZ2V0V29ybGROYW1lcygpLFxuICAgICAgICAgICAgbmV3V29ybGQ6IHRoaXMud29ybGRzLmdldE5leHRXb3JsZE5hbWUoKVxuICAgICAgICB9LCB0aGlzLm1vZGVsLnRvSlNPTigpKTtcblxuICAgICAgICB0aGlzLiRlbC5odG1sKHRlbXBsKHZtKSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIHVwZGF0ZURhdGE6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdGhpcy4kKCdbZGF0YS1maWVsZF0nKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBlbCA9ICQodGhpcyk7XG4gICAgICAgICAgICB2YXIgZmllbGQgPSBlbC5kYXRhKCdmaWVsZCcpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IGVsLnZhbCgpO1xuXG4gICAgICAgICAgICBfdGhpcy5tb2RlbC5zZXQoZmllbGQsIHZhbCk7XG4gICAgICAgIH0pO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQXNzaWdubWVudFJvdzsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBVc2Vyc0NvbGxlY3Rpb24gPSByZXF1aXJlKCcuL3VzZXJzLWNvbGxlY3Rpb24nKTtcbnZhciBXb3JsZHNDb2xsZWN0aW9uID0gcmVxdWlyZSgnLi93b3JsZHMtY29sbGVjdGlvbicpO1xudmFyIFByb2plY3RNb2RlbCA9IHJlcXVpcmUoJy4vcHJvamVjdC1tb2RlbCcpO1xudmFyIEFzc2lnbmVtbnRSb3cgPSByZXF1aXJlKCcuL2Fzc2lnbm1lbnQtcm93Jyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIEFqYXhRdWV1ZSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvYWpheC1xdWV1ZScpO1xuXG5mdW5jdGlvbiBzZXRFbnZpcm9ubWVudChvcHRpb25zKSB7XG4gICAgZW52LnNldChfLm9taXQob3B0aW9ucywgJ2VsJykpO1xufVxuXG52YXIgQXNzaWdubWVudCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgc2V0RW52aXJvbm1lbnQob3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplKG9wdGlvbnMpO1xufTtcblxuQXNzaWdubWVudC5wcm90b3R5cGUgPSB7XG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLmVsID0gdHlwZW9mIG9wdGlvbnMuZWwgPT09ICdzdHJpbmcnID8gJChvcHRpb25zLmVsKVswXSA6IG9wdGlvbnMuZWw7XG4gICAgICAgIHRoaXMuJGVsID0gJCh0aGlzLmVsKTtcbiAgICAgICAgdGhpcy4kID0gXy5wYXJ0aWFsUmlnaHQoJCwgdGhpcy5lbCk7XG5cbiAgICAgICAgdGhpcy51c2VycyA9IG5ldyBVc2Vyc0NvbGxlY3Rpb24oKTtcbiAgICAgICAgdGhpcy53b3JsZHMgPSBuZXcgV29ybGRzQ29sbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnByb2plY3QgPSBuZXcgUHJvamVjdE1vZGVsKCk7XG5cbiAgICAgICAgXy5iaW5kQWxsKHRoaXMsIFsncmVuZGVyJywgJ3JlbmRlclRhYmxlJywgJ3RvZ2dsZUNvbnRyb2xscycsICdzYXZlRWRpdCcsICdzZWxlY3RBbGwnLCAndXNhc3NpZ25TZWxlY3RlZCcsICdfc2hvd1VwZGF0aW5nJywgJ19oaWRlVXBkYXRpbmcnLCAnYXV0b0Fzc2lnbkFsbCcsICdtYWtlVXNlckluYWN0aXZlJ10pO1xuXG4gICAgICAgIHRoaXMuYmluZEV2ZW50cygpO1xuICAgIH0sXG5cbiAgICBiaW5kRXZlbnRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9uKCd1cGRhdGUnLCAndHInLCB0aGlzLnNhdmVFZGl0KTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2lucHV0OmNoZWNrYm94Om5vdCgjc2VsZWN0LWFsbCknLCB0aGlzLnRvZ2dsZUNvbnRyb2xscyk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICcjc2VsZWN0LWFsbCcsIHRoaXMuc2VsZWN0QWxsKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy51bmFzc2lnbi11c2VyJywgdGhpcy51c2Fzc2lnblNlbGVjdGVkKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy5hdXRvLWFzc2lnbi1hbGwnLCB0aGlzLmF1dG9Bc3NpZ25BbGwpO1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnLm1ha2UtdXNlci1pbmFjdGl2ZScsIHRoaXMubWFrZVVzZXJJbmFjdGl2ZSk7XG4gICAgfSxcblxuICAgIGxvYWQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB2YXIgam9pbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLnNldFVzZXJzQ29sbGVjdGlvbih0aGlzLnVzZXJzKTtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLmpvaW5Vc2VycygpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHJldHVybiAkLndoZW4oXG4gICAgICAgICAgICB0aGlzLndvcmxkcy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy51c2Vycy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy5wcm9qZWN0LmZldGNoKClcbiAgICAgICAgKS50aGVuKGpvaW4pO1xuXG4gICAgfSxcblxuICAgIHNhdmVFZGl0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMud29ybGRzLmZldGNoKClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ29udHJvbHMoKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGF1dG9Bc3NpZ25BbGw6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG4gICAgICAgIHZhciBtYXhVc2VycyA9ICt0aGlzLiQoJyNtYXgtdXNlcnMnKS52YWwoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMud29ybGRzLmF1dG9Bc3NpZ25BbGwoeyBtYXhVc2VyczogbWF4VXNlcnMgfSlcbiAgICAgICAgICAgIC5kb25lKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC5mYWlsKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9LFxuXG4gICAgZ2V0U2VsZWN0ZWRJZHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuJCgndGJvZHkgOmNoZWNrYm94OmNoZWNrZWQnKS5tYXAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICQodGhpcykuZGF0YSgnaWQnKTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGZpbmRSb3dWaWV3czogZnVuY3Rpb24gKGlkcykge1xuICAgICAgICByZXR1cm4gXy5tYXAoaWRzLCBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJvd1ZpZXdzW2lkXTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfSxcblxuICAgIHVuYXNzaWduVXNlcnM6IGZ1bmN0aW9uIChpZHMpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIGZvciBub3cgd2UgbmVlZCB0byBzZXF1ZW5jZSB0aGUgY2FsbHMgdG8gdW5hc3NpZ24gdXNlcnMgZnJvbSB3b3JsZHNcbiAgICAgICAgdmFyIHF1ZXVlID0gbmV3IEFqYXhRdWV1ZSgpO1xuXG4gICAgICAgIF8uZWFjaChpZHMsIGZ1bmN0aW9uICh1c2VySWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyID0gdGhpcy51c2Vycy5nZXRCeUlkKHVzZXJJZCk7XG4gICAgICAgICAgICB1c2VyLnNldCgnd29ybGQnLCAnJyk7XG4gICAgICAgICAgICB1c2VyLnNldCgncm9sZScsICcnKTtcbiAgICAgICAgICAgIHF1ZXVlLmFkZChfLnBhcnRpYWwoXy5iaW5kKHRoaXMud29ybGRzLnVwZGF0ZVVzZXIsIHRoaXMud29ybGRzKSwgdXNlcikpO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIHVzYXNzaWduU2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICB2YXIgaWRzID0gdGhpcy5nZXRTZWxlY3RlZElkcygpO1xuXG4gICAgICAgIHZhciBkb25lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy53b3JsZHMuZmV0Y2goKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9oaWRlVXBkYXRpbmcoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudW5hc3NpZ25Vc2VycyhpZHMpLnRoZW4oZG9uZSk7XG4gICAgfSxcblxuICAgIG1ha2VVc2VySW5hY3RpdmU6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdmFyIGlkcyA9IHRoaXMuZ2V0U2VsZWN0ZWRJZHMoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIG1ha2VVc2Vyc0luYWN0aXZlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJvd3MgPSB0aGlzLmZpbmRSb3dWaWV3cyhpZHMpO1xuICAgICAgICAgICAgLy8gZm9yIG5vdyB3ZSBuZWVkIHRvIHNlcXVlbmNlIHRoZSBjYWxscyB0byBwYXRjaCB0aGUgdXNlcnNcbiAgICAgICAgICAgIC8vIHNpbmNlIHRoZSBBUEkgY2FuIG9ubHkgb3BlcmF0ZSBvbiBvbmUgY2FsbCBwZXIgZ3JvdXAgYXQgYSB0aW1lXG4gICAgICAgICAgICB2YXIgcXVldWUgPSBuZXcgQWpheFF1ZXVlKCk7XG4gICAgICAgICAgICBfLmVhY2gocm93cywgZnVuY3Rpb24gKHZpZXcpIHtcbiAgICAgICAgICAgICAgICB2YXIgdXNlciA9IHZpZXcubW9kZWw7XG4gICAgICAgICAgICAgICAgcXVldWUuYWRkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZpZXcubWFrZUluYWN0aXZlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZXcucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gdGhpcy51bmFzc2lnblVzZXJzKGlkcylcbiAgICAgICAgICAgIC50aGVuKG1ha2VVc2Vyc0luYWN0aXZlKTtcblxuXG4gICAgfSxcblxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiQoJ3RhYmxlIHRib2R5JykuZW1wdHkoKTtcbiAgICAgICAgdGhpcy5yZW5kZXJUYWJsZSgpO1xuICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgIH0sXG5cbiAgICByZW5kZXJUYWJsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJvd1ZpZXdzID0ge307XG4gICAgICAgIHZhciByb3dzID0gW107XG4gICAgICAgIHRoaXMudXNlcnMuZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgQXNzaWduZW1udFJvdyh7IG1vZGVsOiB1LCB3b3JsZHM6IHRoaXMud29ybGRzLCBwcm9qZWN0OiB0aGlzLnByb2plY3QgfSk7XG4gICAgICAgICAgICB0aGlzLnJvd1ZpZXdzW3UuZ2V0KCdpZCcpXSA9IHZpZXc7XG4gICAgICAgICAgICByb3dzLnB1c2godmlldy5yZW5kZXIoKS5lbCk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHRoaXMuJCgndGFibGUgdGJvZHknKS5hcHBlbmQocm93cyk7XG4gICAgfSxcblxuXG4gICAgdXBkYXRlQ29udHJvbHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9sc0ZvclNlbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnVwZGF0ZUF1dG9Bc3NpZ25CdXR0b24oKTtcbiAgICAgICAgdGhpcy51cGRhdGVTdGF0dXMoKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlU3RhdHVzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbmNvbHBsZXRlV29ybGRzID0gdGhpcy53b3JsZHMuZ2V0SW5jb21wbGV0ZVdvcmxkc0NvdW50KCk7XG4gICAgICAgIHZhciB1bmFzc2lnbmVkVXNlcnMgPSB0aGlzLnVzZXJzLmdldFVuYXNzaWduZWRVc2Vyc0NvdW50KCk7XG4gICAgICAgIHZhciB0b3RhbFdvcmxkcyA9IHRoaXMud29ybGRzLnNpemUoKTtcblxuICAgICAgICB2YXIgdXNlcnNUZXh0ID0gdW5hc3NpZ25lZFVzZXJzID8gdW5hc3NpZ25lZFVzZXJzID09PSAxID8gJzEgdXNlciBuZWVkcyBhc3NpZ25tZW50LicgOiB1bmFzc2lnbmVkVXNlcnMgKyAnIHVzZXJzIG5lZWQgYXNzaWdubWVudC4nIDogJ0FsbCB1c2VycyBoYXZlIGJlZW4gYXNzaWduZWQuJztcbiAgICAgICAgdmFyIHdvcmxkc1RleHQgPSAhdG90YWxXb3JsZHMgPyAnTm8gd29ybGRzIGhhdmUgYmVlbiBjcmVhdGVkLicgOiAhaW5jb2xwbGV0ZVdvcmxkcyA/ICdBbGwgd29ybGRzIGFyZSBjb21wbGV0ZS4nIDogaW5jb2xwbGV0ZVdvcmxkcyA9PT0gMSA/ICcxIGluY29tcGxldGUgd29ybGQgbmVlZHMgYXR0ZW50aW9uLicgOiBpbmNvbHBsZXRlV29ybGRzICsgJyBpbmNvbXBsZXRlIHdvcmxkcyBuZWVkIGF0dGVudGlvbi4nO1xuXG4gICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cyAudGV4dCcpLnRleHQodXNlcnNUZXh0KTtcbiAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cyAudGV4dCcpLnRleHQod29ybGRzVGV4dCk7XG5cbiAgICAgICAgaWYgKHVuYXNzaWduZWRVc2Vycykge1xuICAgICAgICAgICAgdGhpcy4kKCcjdXNlcnMtc3RhdHVzJykuYWRkQ2xhc3MoJ2luY29tcGxldGUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5jb2xwbGV0ZVdvcmxkcyB8fCAhdG90YWxXb3JsZHMpIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3dvcmxkcy1zdGF0dXMnKS5hZGRDbGFzcygnaW5jb21wbGV0ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLiQoJy5zdGF0dXMtd2lkZ2V0JykuYWRkQ2xhc3MoJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQ29udHJvbHNGb3JTZWxlY3Rpb246IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG51bVNlbGVjdGVkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpLmxlbmd0aDtcbiAgICAgICAgdGhpcy4kKCcuY29tcG9uZW50LmNvbnRyb2xzJylbbnVtU2VsZWN0ZWQgPyAnYWRkQ2xhc3MnIDogJ3JlbW92ZUNsYXNzJ10oJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQXV0b0Fzc2lnbkJ1dHRvbjogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIGlmICh0aGlzLnByb2plY3QuaXNEeW5hbWljQXNzaWdubWVudCgpKSB7XG4gICAgICAgICAgICB2YXIgaGFzUm9sZXMgPSB0aGlzLnByb2plY3QuaGFzUm9sZXMoKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5zaW5nbGUnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYycpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5keW5hbWljLW5vLXJvbGVzLXRleHQnKVtoYXNSb2xlcyA/ICdoaWRlJyA6ICdzaG93J10oKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpW2hhc1JvbGVzID8gJ2hpZGUnIDogJ3Nob3cnXSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLmR5bmFtaWMnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYy1uby1yb2xlcy10ZXh0JykuaGlkZSgpO1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLnNpbmdsZScpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpLnNob3coKTtcblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudXNlcnMuYWxsVXNlcnNBc3NpZ25lZCgpKSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLnJlbW92ZUNsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLmFkZENsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc2VsZWN0QWxsOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICB0aGlzLiQoJ3Rib2R5IDpjaGVja2JveCcpLnByb3AoJ2NoZWNrZWQnLCBlLnRhcmdldC5jaGVja2VkKTtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICB0b2dnbGVDb250cm9sbHM6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB0b3RhbCA9IHRoaXMuJCgndGJvZHkgOmNoZWNrYm94Jyk7XG4gICAgICAgIHZhciBjaGVja2VkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpO1xuXG4gICAgICAgIGlmICh0b3RhbC5sZW5ndGggPT09IGNoZWNrZWQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykuYXR0cignY2hlY2tlZCcsICdjaGVja2VkJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykucmVtb3ZlQXR0cignY2hlY2tlZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICBfc2hvd1VwZGF0aW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLmNzcyh7IG9wYWNpdHk6IDAuNCB9KTtcbiAgICB9LFxuXG4gICAgX2hpZGVVcGRhdGluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5jc3MoeyBvcGFjaXR5OiAxIH0pO1xuICAgIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBc3NpZ25tZW50OyIsIid1c2Ugc3RyaWN0JztcblxudmFyIEJhc2VDb2xsZWN0aW9uID0gZnVuY3Rpb24gKG1vZGVscywgb3B0aW9ucykge1xuICAgIHRoaXMuX21vZGVscyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlQ29sbGVjdGlvbi5wcm90b3R5cGUsIHtcbiAgICBpZEF0dHJpYnV0ZTogJ2lkJyxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uIChtb2RlbHMsIG9wdGlvbnMpIHtcbiAgICB9LFxuXG4gICAgY3JlYXRlOiBmdW5jdGlvbiAoYXR0ciwgb3B0aW9ucykge1xuICAgICAgICB2YXIgbSA9IG5ldyB0aGlzLm1vZGVsKGF0dHIsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnNldChtKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAobW9kZWxzLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMuX21vZGVscy5sZW5ndGggPSAwO1xuICAgICAgICB0aGlzLnNldChtb2RlbHMpO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uIChtb2RlbCkge1xuICAgICAgICBfLnJlbW92ZSh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbSA9PT0gbW9kZWw7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGRlbGV0ZSBtb2RlbC5jb2xsZWN0aW9uO1xuXG4gICAgICAgIHJldHVybiBtb2RlbDtcbiAgICB9LFxuXG4gICAgc2V0OiBmdW5jdGlvbiAobW9kZWxzKSB7XG4gICAgICAgIGlmICghbW9kZWxzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBtb2RlbHMgPSBbXS5jb25jYXQobW9kZWxzKTtcblxuICAgICAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIF8uZWFjaChtb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICBpZiAoIShtIGluc3RhbmNlb2YgdGhpcy5tb2RlbCkpIHtcbiAgICAgICAgICAgICAgICBtID0gbmV3IHRoaXMubW9kZWwobSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG0uY29sbGVjdGlvbiA9IHRoaXM7XG5cbiAgICAgICAgICAgIHRoaXMuX21vZGVscy5wdXNoKG0pO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICB0aGlzLnNvcnQuY2FsbCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gbW9kZWxzO1xuICAgIH0sXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBiLl9kYXRhW3RoaXMuaWRBdHRyaWJ1dGVdIC0gYS5fZGF0YVt0aGlzLmlkQXR0cmlidXRlXTtcbiAgICB9LFxuXG4gICAgc29ydDogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLl9tb2RlbHMgPSB0aGlzLl9tb2RlbHMuc29ydCh0aGlzLnNvcnRGbi5iaW5kKHRoaXMpKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzO1xuICAgIH0sXG5cbiAgICBnZXRCeUlkOiBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgcmV0dXJuIF8uZmluZCh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbS5nZXQodGhpcy5pZEF0dHJpYnV0ZSkgPT09IGlkO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgZWFjaDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uZWFjaCh0aGlzLl9tb2RlbHMsIGNiLCBjdHggfHwgdGhpcyk7XG4gICAgfSxcblxuICAgIGFsbDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uYWxsKHRoaXMuX21vZGVscywgY2IsIGN0eCB8fCB0aGlzKTtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBfLmludm9rZSh0aGlzLl9tb2RlbHMsICd0b0pTT04nKTtcbiAgICB9LFxuXG4gICAgZmluZDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbmQodGhpcy5fbW9kZWxzLCBmbik7XG4gICAgfSxcblxuICAgIGZpbHRlcjogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbHRlcih0aGlzLl9tb2RlbHMsIGZuKTtcbiAgICB9LFxuXG4gICAgc2l6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgbWFwOiBmdW5jdGlvbiAoZm4sIGN0eCkge1xuICAgICAgICByZXR1cm4gXy5tYXAodGhpcy5fbW9kZWxzLCBmdW5jdGlvbiAobW9kZWwpIHtcbiAgICAgICAgICAgIHJldHVybiBmbi5jYWxsKGN0eCwgbW9kZWwudG9KU09OKCkpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgcGx1Y2s6IGZ1bmN0aW9uIChmaWVsZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBtW2ZpZWxkXTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlQ29sbGVjdGlvbjsiLCIndXNlIHN0cmljdCc7XG5cblxudmFyIEJhc2VNb2RlbCA9IGZ1bmN0aW9uIChhdHRyLCBvcHRpb25zKSB7XG4gICAgYXR0ciA9IF8uZGVmYXVsdHMoe30sIGF0dHIsIF8ucmVzdWx0KHRoaXMsICdkZWZhdWx0cycpKTtcbiAgICB0aGlzLl9kYXRhID0ge307XG4gICAgdGhpcy5zZXQoYXR0ciwgb3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlTW9kZWwucHJvdG90eXBlLCB7XG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKGF0dHIsIG9wdGlvbnMpIHtcblxuICAgIH0sXG5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbCwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChrZXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWw7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBfLmV4dGVuZCh0aGlzLl9kYXRhLCBhdHRycyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGdldDogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YVtrZXldO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jb2xsZWN0aW9uLnJlbW92ZSh0aGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICB0b0pTT046IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGE7XG4gICAgfSxcblxuICAgIHBpY2s6IGZ1bmN0aW9uIChrZXlzKSB7XG4gICAgICAgIHJldHVybiBfLnBpY2sodGhpcy5fZGF0YSwga2V5cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlTW9kZWw7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZW52ID0ge1xuICAgIGFjY291bnQ6ICcnLFxuICAgIHByb2plY3Q6ICcnLFxuICAgIGdyb3VwOiAnJyxcbiAgICBncm91cElkOiAnJyxcbiAgICB0b2tlbjogJycsXG4gICAgc2VydmVyOiB7XG4gICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgcHJvdG9jb2w6ICdodHRwcydcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBzZXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGVudiA9IF8ubWVyZ2UoZW52LCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBlbnY7XG4gICAgfVxufTsiLCIoZnVuY3Rpb24gKCkge1xuICAgICd1c2Ugc3RyaWN0JztcbiAgICB2YXIgQXBwID0gcmVxdWlyZSgnLi9hc3NpZ25tZW50LmpzJyk7XG5cbiAgICB3aW5kb3cuZm9yaW8gPSB3aW5kb3cuZm9yaW8gfHwge307XG4gICAgd2luZG93LmZvcmlvLk11bHRpcGxheWVyQXNzaWdubWVudENvbXBvbmVudCA9IEFwcDtcbn0pKCk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBzZXJ2aWNlTG9jYXRvciA9IHJlcXVpcmUoJy4vc2VydmljZS1sb2NhdG9yJyk7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG4vLyB2YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBpc0R5bmFtaWNBc3NpZ25tZW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldCgnd29ybGRzJykgPT09ICdkeW5hbWljJztcbiAgICB9LFxuXG4gICAgaGFzUm9sZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJvbGVzID0gdGhpcy5nZXQoJ3JvbGVzJyk7XG4gICAgICAgIHJldHVybiByb2xlcyAmJiAhIXJvbGVzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGFwaSA9IHNlcnZpY2VMb2NhdG9yLndvcmxkQXBpKCk7XG5cbiAgICAgICAgcmV0dXJuIGFwaS5nZXRQcm9qZWN0U2V0dGluZ3MoKS50aGVuKGZ1bmN0aW9uIChzZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5zZXQoc2V0dGluZ3MpO1xuICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cbn0pOyIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVudiA9IHJlcXVpcmUoJy4vZGVmYXVsdHMuanMnKTtcblxudmFyIGNhY2hlID0ge307XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHdvcmxkQXBpOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghY2FjaGUud29ybGRBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLndvcmxkQXBpID0gbmV3IEYuc2VydmljZS5Xb3JsZChlbnYuZ2V0KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLndvcmxkQXBpO1xuICAgIH0sXG5cbiAgICBtZW1iZXJBcGk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFjYWNoZS5tZW1iZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLm1lbWJlckFwaSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKF8ucGljayhlbnYuZ2V0KCksIFsnZ3JvdXBJZCcsICdzZXJ2ZXInXSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLm1lbWJlckFwaTtcbiAgICB9LFxuXG4gICAgdXNlckFwaTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIWNhY2hlLnVzZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLnVzZXJBcGkgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoXy5waWNrKGVudi5nZXQoKSwgWydhY2NvdW50JywgJ3NlcnZlciddKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2FjaGUudXNlckFwaTtcbiAgICB9XG59OyIsImV4cG9ydHNbXCJlZGl0LXVzZXItcm93XCJdID0gZnVuY3Rpb24ob2JqKSB7XG5vYmogfHwgKG9iaiA9IHt9KTtcbnZhciBfX3QsIF9fcCA9ICcnLCBfX2UgPSBfLmVzY2FwZSwgX19qID0gQXJyYXkucHJvdG90eXBlLmpvaW47XG5mdW5jdGlvbiBwcmludCgpIHsgX19wICs9IF9fai5jYWxsKGFyZ3VtZW50cywgJycpIH1cbndpdGggKG9iaikge1xuX19wICs9ICc8dGQ+PGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGNsYXNzPVwic2VsZWN0XCIgZGF0YS1pZD1cIicgK1xuKChfX3QgPSAoIGlkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+PC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cIndvcmxkc1wiIGNsYXNzPVwiZm9ybS1jb250cm9sXCIgZGF0YS1maWVsZD1cIndvcmxkXCI+XFxuXFxuICAgICc7XG4gXy5lYWNoKHdvcmxkcywgZnVuY3Rpb24gKHcpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHcgPT09IHdvcmxkID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIicgK1xuKChfX3QgPSAoIG5ld1dvcmxkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiIGNsYXNzPVwibmV3LXdvcmxkLXRleHRcIj48aT4nICtcbigoX190ID0gKCBuZXdXb3JsZCApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbicgLSBOZXcgLTwvaT48L29wdGlvbj5cXG4gICAgPC9zZWxlY3Q+XFxuPC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cInJvbGVzXCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBkYXRhLWZpZWxkPVwicm9sZVwiPlxcbiAgICAnO1xuIF8uZWFjaChyb2xlcywgZnVuY3Rpb24gKHIpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHIgPT09IHJvbGUgPyAnc2VsZWN0ZWQnIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPicgK1xuKChfX3QgPSAoIHIgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC9vcHRpb24+XFxuICAgICc7XG4gfSk7IDtcbl9fcCArPSAnXFxuXFxuICAgICc7XG4gXy5lYWNoKG9wdGlvbmFsUm9sZXMsIGZ1bmN0aW9uIChyKSB7IDtcbl9fcCArPSAnXFxuICAgICAgICA8b3B0aW9uIHZhbHVlPVwiJyArXG4oKF9fdCA9ICggciApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbidcIiAnICtcbigoX190ID0gKCByID09PSByb2xlID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJyA8aT4oT3B0aW9uYWwpPC9pPjwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICA8L3NlbGVjdD5cXG48L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi10b29scyBidG4tc2F2ZSBzYXZlXCI+U2F2ZTwvYnV0dG9uPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi10b29scyBidG4tY2FuY2VsIGNhbmNlbFwiPkNhbmNlbDwvYnV0dG9uPlxcbjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTtcbmV4cG9ydHNbXCJ1c2VyLXJvd1wiXSA9IGZ1bmN0aW9uKG9iaikge1xub2JqIHx8IChvYmogPSB7fSk7XG52YXIgX190LCBfX3AgPSAnJywgX19lID0gXy5lc2NhcGU7XG53aXRoIChvYmopIHtcbl9fcCArPSAnPHRkPjxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cInNlbGVjdFwiIGRhdGEtaWQ9XCInICtcbigoX190ID0gKCBpZCkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggIWlzV29ybGRDb21wbGV0ZSA/ICc8ZW0gY2xhc3M9XCJmLWljb24gZi13YXJuaW5nXCI+PC9lbT4nIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggd29ybGQgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggcm9sZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPjxidXR0b24gY2xhc3M9XCJidG4gZWRpdCBidG4tZWRpdCBidG4tdG9vbHMgYXV0by1oaWRlXCI+RWRpdDwvYnV0dG9uPjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBkZWZhdWx0czoge1xuICAgICAgICB3b3JsZDogJycsXG4gICAgICAgIHJvbGU6ICcnLFxuICAgICAgICBhY3RpdmU6IHRydWUsXG4gICAgICAgIGlzV29ybGRDb21wbGV0ZTogdHJ1ZSxcbiAgICAgICAgZmlyc3ROYW1lOiAnJyxcbiAgICAgICAgbGFzdE5hbWU6ICcnXG4gICAgfSxcblxuICAgIG1ha2VBY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gbWVtYmVyQXBpLm1ha2VVc2VyQWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBtYWtlSW5hY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBmYWxzZSk7XG5cbiAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5tYWtlVXNlckluYWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cblxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcblxudmFyIE1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcblxuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBtb2RlbDogTW9kZWwsXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHZhciBhdyA9IGEuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBidyA9IGIuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIGlmIChhdyAhPT0gYncpIHtcbiAgICAgICAgICAgIHJldHVybiBhdyA8IGJ3ID8gLTEgOiAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGIuZ2V0KCd1c2VyTmFtZScpID4gYS5nZXQoJ3VzZXJOYW1lJykgPyAtMSA6IDE7XG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJC5hamF4U2V0dXAoe1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIGVudi5nZXQoKS50b2tlblxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgYWxsVXNlcnNBc3NpZ25lZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hbGwoZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiAhIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0VW5hc3NpZ25lZFVzZXJzQ291bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmlsdGVyKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICByZXR1cm4gIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KS5sZW5ndGg7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBncm91cElkID0gZW52LmdldCgpLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGdldEdyb3VwVXNlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbWVtYmVyQXBpID0gc2VydmljZUxvY2F0b3IubWVtYmVyQXBpKCk7XG4gICAgICAgICAgICB2YXIgdXNlckFwaSA9IHNlcnZpY2VMb2NhdG9yLnVzZXJBcGkoKTtcblxuICAgICAgICAgICAgdmFyIGxvYWRHcm91cE1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5nZXRHcm91cERldGFpbHMoKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBsb2FkVXNlcnNJbmZvID0gZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vbkZhY0FuZEFjdGl2ZSA9IGZ1bmN0aW9uICh1KSB7IHJldHVybiB1LmFjdGl2ZSAmJiB1LnJvbGUgIT09ICdmYWNpbGl0YXRvcic7IH07XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJzID0gXy5wbHVjayhfLmZpbHRlcihncm91cC5tZW1iZXJzLCBub25GYWNBbmRBY3RpdmUpLCAndXNlcklkJyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVzZXJBcGkuZ2V0KHsgaWQ6IHVzZXJzIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGxvYWRHcm91cE1lbWJlcnMoKVxuICAgICAgICAgICAgICAgIC50aGVuKGxvYWRVc2Vyc0luZm8pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgZ2V0R3JvdXBVc2VycygpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAodXNlcnMpIHtcbiAgICAgICAgICAgICAgICB1c2VycyA9IF8ubWFwKHVzZXJzLCBmdW5jdGlvbiAodSkgeyByZXR1cm4gXy5leHRlbmQodSwgeyBncm91cElkOiBncm91cElkIH0pOyB9KTtcbiAgICAgICAgICAgICAgICBfdGhpcy5zZXQodXNlcnMpO1xuICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHVzZXJzLCBfdGhpcyk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9XG5cbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBkZWZhdWx0czoge1xuICAgICAgICB1c2VyczogbnVsbCxcbiAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX19zdXBlci5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgdGhpcy5fZGF0YS51c2VycyA9IHRoaXMuX2RhdGEudXNlcnMgfHwgW107XG5cbiAgICAgICAgdGhpcy5fd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuXG4gICAgICAgIHZhciBpZCA9IHRoaXMuZ2V0KCdpZCcpO1xuICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgYWRkVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIHVzZXJzLnB1c2godXNlcik7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuc2F2ZSgpO1xuICAgIH0sXG5cbiAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlcikge1xuICAgICAgICB2YXIgaWQgPSB0aGlzLmdldCgnaWQnKTtcbiAgICAgICAgdmFyIGNoZWNrV29ybGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuZ2V0KCd1c2VycycpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSkuZGVsZXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICBfLnJlbW92ZSh0aGlzLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiB1LmdldCgnaWQnKSA9PT0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl93b3JsZEFwaVxuICAgICAgICAgICAgLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSlcbiAgICAgICAgICAgIC5yZW1vdmVVc2VyKHsgdXNlcklkOiB1c2VyLmdldCgnaWQnKSB9KVxuICAgICAgICAgICAgLnRoZW4oY2hlY2tXb3JsZCk7XG4gICAgfSxcblxuICAgIHNhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIG1hcFVzZXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIF8ubWFwKHRoaXMuZ2V0KCd1c2VycycpLCBmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgICAgIHZhciByZXMgPSB7IHVzZXJJZDogdS5nZXQoJ2lkJykgfTtcbiAgICAgICAgICAgICAgICB2YXIgcm9sZSA9IHUuZ2V0KCdyb2xlJyk7XG5cbiAgICAgICAgICAgICAgICBpZiAocm9sZSkge1xuICAgICAgICAgICAgICAgICAgICByZXMucm9sZSA9IHJvbGU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIGNyZWF0ZVdvcmxkID0gXy5wYXJ0aWFsKHRoaXMuX3dvcmxkQXBpLmNyZWF0ZSwgdGhpcy5waWNrKFsnbW9kZWwnLCAnbmFtZScsICdtaW5Vc2VycyddKSk7XG4gICAgICAgIHZhciBhZGRVc2VycyA9IF8ucGFydGlhbChfdGhpcy5fd29ybGRBcGkuYWRkVXNlcnMsIG1hcFVzZXJzKCksIHsgZmlsdGVyOiBfdGhpcy5nZXQoJ2lkJykgfSk7XG4gICAgICAgIHZhciBzYXZlZFVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIGlmICh0aGlzLmlzTmV3KCkpIHtcbiAgICAgICAgICAgIC8vIHdlIG5lZWQgdG8gY3JlYXRlIHRoZSB3b3JsZCBpbiB0aGUgQVBJIGFuZCB0aGVuIGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVXb3JsZCgpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNldCh3b3JsZCk7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLl93b3JsZEFwaS51cGRhdGVDb25maWcoeyBmaWx0ZXI6IHdvcmxkLmlkIH0pO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oYWRkVXNlcnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHVzZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHNpbmNlIHdlIHJlLXNldCB0aGUgd29ybGQsIHJlLXNldCB0aGUgdXNlcnNcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuc2V0KCd1c2VycycsIHNhdmVkVXNlcnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gdGhlIHdvcmxkIGlzIGFscmVhZHkgY3JlYXRlZCBqdXN0IGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBhZGRVc2VycygpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGlzTmV3OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5nZXQoJ2xhc3RNb2RpZmllZCcpO1xuICAgIH1cblxufSk7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgTW9kZWwgPSByZXF1aXJlKCcuL3dvcmxkLW1vZGVsJyk7XG52YXIgVXNlck1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG52YXIgZG9uZUZuID0gZnVuY3Rpb24gKGR0ZCwgYWZ0ZXIpIHtcbiAgICByZXR1cm4gXy5hZnRlcihhZnRlciwgZHRkLnJlc29sdmUpO1xufTtcblxudmFyIHdvcmxkQXBpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgbW9kZWw6IE1vZGVsLFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBfX3N1cGVyLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuICAgIH0sXG5cbiAgICBhdXRvQXNzaWduQWxsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gd29ybGRBcGkuYXV0b0Fzc2lnbihvcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzZXQodGhpcy5wYXJzZSh3b3JsZHMpKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGdldEluY29tcGxldGVXb3JsZHNDb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24gKHcpIHtcbiAgICAgICAgICAgIHJldHVybiAhdy5nZXQoJ2NvbXBsZXRlJyk7XG4gICAgICAgIH0pLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgdXBkYXRlVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHdvcmxkTmFtZSA9IHVzZXIuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgcHJldldvcmxkID0gdGhpcy5nZXRXb3JsZEJ5VXNlcih1c2VyKTtcbiAgICAgICAgdmFyIGN1cldvcmxkID0gdGhpcy5nZXRPckNyZWF0ZVdvcmxkKHdvcmxkTmFtZSk7XG4gICAgICAgIHZhciBkb25lID0gZG9uZUZuKGR0ZCwgMSk7XG5cbiAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUncyBhbnl0aGluZyB0byBkb1xuICAgICAgICBpZiAoIXByZXZXb3JsZCAmJiAhY3VyV29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiBkdGQucmVzb2x2ZSgpLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwcmV2V29ybGQpIHtcbiAgICAgICAgICAgIHByZXZXb3JsZC5yZW1vdmVVc2VyKHVzZXIpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY3VyV29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjdXJXb3JsZC5hZGRVc2VyKHVzZXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAudGhlbihkb25lKTtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJXb3JsZCkge1xuICAgICAgICAgICAgY3VyV29ybGQuYWRkVXNlcih1c2VyKVxuICAgICAgICAgICAgICAgIC50aGVuKGRvbmUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldE9yQ3JlYXRlV29ybGQ6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgaWYgKCF3b3JsZE5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB3b3JsZCA9IHRoaXMuZ2V0V29yZEJ5TmFtZSh3b3JsZE5hbWUpO1xuXG4gICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgIHdvcmxkID0gdGhpcy5jcmVhdGUoeyBuYW1lOiB3b3JsZE5hbWUgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gd29ybGQ7XG4gICAgfSxcblxuICAgIGdldFdvcmRCeU5hbWU6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmluZChmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiB3b3JsZC5nZXQoJ25hbWUnKSA9PT0gd29ybGROYW1lO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGRCeVVzZXI6IGZ1bmN0aW9uICh1c2VyKSB7XG4gICAgICAgIGlmICghdXNlci5nZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZ2V0V29ybGRCeVVzZXIgZXhwZWN0ZXMgYSBtb2RlbCAoJyArIHVzZXIgKyAnKScpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGlkID0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFdvcmxkQnlVc2VySWQoaWQpO1xuICAgIH0sXG5cbiAgICBnZXRXb3JsZEJ5VXNlcklkOiBmdW5jdGlvbiAodXNlcklkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZpbmQoZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICByZXR1cm4gXy5maW5kKHdvcmxkLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdS5nZXQoJ2lkJykgPT09IHVzZXJJZDtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGROYW1lczogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wbHVjaygnbmFtZScpO1xuICAgIH0sXG5cbiAgICBnZXROZXh0V29ybGROYW1lOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBwYWQgPSBmdW5jdGlvbiAobnVtLCBwbGFjZXMpIHtcbiAgICAgICAgICAgIHZhciB6ZXJvcyA9ICcwMDAwMDAwMDAwMDAwMDAwMDAnO1xuICAgICAgICAgICAgdmFyIGRpZ2l0cyA9IG51bS50b1N0cmluZygpLmxlbmd0aDtcbiAgICAgICAgICAgIHZhciBuZWVkZWQgPSBwbGFjZXMgLSBkaWdpdHM7XG4gICAgICAgICAgICByZXR1cm4gemVyb3Muc3Vic3RyKDAsIG5lZWRlZCkgKyBudW07XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHdvcmxkcyA9IHRoaXMuZ2V0V29ybGROYW1lcygpO1xuXG4gICAgICAgIGlmICghd29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuICdXb3JsZDAwMSc7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcHJvcGVyTmFtZXMgPSBfLmZpbHRlcih3b3JsZHMsIGZ1bmN0aW9uICh3KSB7IHJldHVybiAvV29ybGRcXGRcXGRcXGQvLnRlc3Qodyk7IH0pLnNvcnQoKTtcbiAgICAgICAgdmFyIGxhc3RXb3JsZCA9IHByb3Blck5hbWVzW3Byb3Blck5hbWVzLmxlbmd0aCAtIDFdO1xuICAgICAgICB2YXIgbnVtV29ybGQgPSArbGFzdFdvcmxkLm1hdGNoKC9Xb3JsZChcXGRcXGRcXGQpLylbMV07XG4gICAgICAgIHJldHVybiAnV29ybGQnICsgcGFkKG51bVdvcmxkICsgMSwgMyk7XG4gICAgfSxcblxuICAgIHNldFVzZXJzQ29sbGVjdGlvbjogZnVuY3Rpb24gKHVzZXJzQ29sbGVjdGlvbikge1xuICAgICAgICB0aGlzLnVzZXJzQ29sbGVjdGlvbiA9IHVzZXJzQ29sbGVjdGlvbjtcbiAgICB9LFxuXG4gICAgam9pblVzZXJzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1c2Vyc0hhc2ggPSB7fTtcbiAgICAgICAgdmFyIHVzZXJzQ29sbGVjdGlvbiA9IHRoaXMudXNlcnNDb2xsZWN0aW9uO1xuICAgICAgICB1c2Vyc0NvbGxlY3Rpb24uZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdS5zZXQoeyBpc1dvcmxkQ29tcGxldGU6IHRydWUgfSk7XG4gICAgICAgICAgICByZXR1cm4gKHVzZXJzSGFzaFt1LmdldCgnaWQnKV0gPSB1KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5lYWNoKGZ1bmN0aW9uICh3LCBpKSB7XG4gICAgICAgICAgICB2YXIgbmFtZSA9IHcuZ2V0KCduYW1lJyk7XG4gICAgICAgICAgICB2YXIgaXNDb21wbGV0ZSA9IHcuZ2V0KCdjb21wbGV0ZScpO1xuICAgICAgICAgICAgdy5zZXQoeyBpbmRleDogaSwgbmFtZTogbmFtZSB8fCAoaSArIDEpICsgJycgfSk7XG4gICAgICAgICAgICBfLmVhY2gody5nZXQoJ3VzZXJzJyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgaWYgKHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldKSB7XG4gICAgICAgICAgICAgICAgICAgIHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldLnNldCh7IHdvcmxkOiBuYW1lLCByb2xlOiB1LmdldCgncm9sZScpLCBpc1dvcmxkQ29tcGxldGU6IGlzQ29tcGxldGUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHVzZXJzQ29sbGVjdGlvbi5zb3J0KCk7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB3b3JsZEFwaS5saXN0KClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc2V0KHRoaXMucGFyc2Uod29ybGRzKSk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBwYXJzZTogZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICBpZiAod29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgd29ybGRzID0gXy5tYXAod29ybGRzLCBmdW5jdGlvbiAodykge1xuICAgICAgICAgICAgICAgIHZhciB1c2VycyA9IF8ubWFwKHcudXNlcnMsIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGluIHRoZSB3b3JsZCBhcGkgdXNlcnMgSWRzIGNvbWVzIGFzIHVzZXJJZFxuICAgICAgICAgICAgICAgICAgICAvLyBtYWtlIHN1cmUgd2UgYWRkIGl0IGFzIGlkIHNvIHdlIGNhbiB1c2UgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIHNhbWUgY29kZSB0byBhY2Nlc3MgbW9kZWxzIHRoYXQgY29tZSBmcm9tIHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyBtZW1iZXIvbG9jYWwgYXBpIGFzIHdpdGggdGhlIHdvcmxkIGFwaVxuICAgICAgICAgICAgICAgICAgICB1LmlkID0gdS51c2VySWQ7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVXNlck1vZGVsKHUpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgdy51c2VycyA9IHVzZXJzO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHc7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB3b3JsZHM7XG4gICAgfVxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuKiBVdGlsaXR5IGNsYXNzIHRvIG1ha2UgYWpheCBjYWxscyBzZXF1ZW5jaWFsXG4qL1xuZnVuY3Rpb24gQWpheFF1ZXVlICgpIHtcbiAgICB0aGlzLnF1ZXVlID0gW107XG59XG5cbiQuZXh0ZW5kKEFqYXhRdWV1ZS5wcm90b3R5cGUsIHtcbiAgICBhZGQ6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICByZXR1cm4gdGhpcy5xdWV1ZS5wdXNoKGZuKTtcbiAgICB9LFxuXG4gICAgZXhlY3V0ZTogZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgY29udGV4dCA9IGNvbnRleHQgfHwgdGhpcztcblxuICAgICAgICBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgICAgICAgaWYgKF90aGlzLnF1ZXVlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBmbiA9IF90aGlzLnF1ZXVlLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgICAgICBmbi5jYWxsKGNvbnRleHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKG5leHQpXG4gICAgICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbmV4dCgpO1xuXG4gICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQWpheFF1ZXVlOyIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiJdfQ== +//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Fzc2lnbm1lbnQtcm93LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9hc3NpZ25tZW50LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9iYXNlLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Jhc2UtbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2RlZmF1bHRzLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9pbmRleC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvcHJvamVjdC1tb2RlbC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvc2VydmljZS1sb2NhdG9yLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy90ZW1wbGF0ZXMuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXItbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXJzLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3dvcmxkLW1vZGVsLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy93b3JsZHMtY29sbGVjdGlvbi5qcyIsInNyYy91dGlsL2FqYXgtcXVldWUuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCc7XG5cbnZhciB0ZW1wbGF0ZXMgPSByZXF1aXJlKCcuL3RlbXBsYXRlcycpO1xuXG52YXIgQXNzaWdubWVudFJvdyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy4kZWwgPSAkKCc8dHI+Jyk7XG4gICAgdGhpcy5lbCA9IHRoaXMuJGVsWzBdO1xuICAgIHRoaXMuJCA9IF8ucGFydGlhbFJpZ2h0KCQsIHRoaXMuJGVsKTtcblxuICAgIHRoaXMubW9kZWwgPSBvcHRpb25zLm1vZGVsO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy53b3JsZHMgPSBvcHRpb25zLndvcmxkcztcbiAgICB0aGlzLnByb2plY3QgPSBvcHRpb25zLnByb2plY3Q7XG5cbiAgICBfLmJpbmRBbGwodGhpcywgWydzZXRFZGl0TW9kZScsICdyZW1vdmVFZGl0TW9kZScsICdzYXZlRWRpdCcsICdjYW5jZWxFZGl0JywgJ3VwZGF0ZURhdGEnXSk7XG5cbiAgICB0aGlzLmJpbmRFdmVudHMoKTtcblxufTtcblxuXy5leHRlbmQoQXNzaWdubWVudFJvdy5wcm90b3R5cGUsIHtcblxuICAgIHRlbXBsYXRlOiB0ZW1wbGF0ZXNbJ3VzZXItcm93J10sXG5cbiAgICBlZGl0VGVtcGxhdGU6IHRlbXBsYXRlc1snZWRpdC11c2VyLXJvdyddLFxuXG4gICAgYmluZEV2ZW50czogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnYnV0dG9uLmVkaXQnLCB0aGlzLnNldEVkaXRNb2RlKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2J1dHRvbi5zYXZlJywgdGhpcy5zYXZlRWRpdCk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICdidXR0b24uY2FuY2VsJywgdGhpcy5jYW5jZWxFZGl0KTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9mZignY2xpY2snLCBudWxsLCBudWxsKTtcbiAgICAgICAgLy8gdGhpcyBvbmx5IGdpdmVzIGEgZGVsYXkgdG8gcmVtb3ZlIHRoZSB0clxuICAgICAgICAvLyBhbmltYXRpb24gb2YgaGVpZ2h0IG9mIHRoZSB0ciBkb2VzIG5vdCB3b3JrXG4gICAgICAgIHRoaXMuJCgnOmNoZWNrYm94JykuYXR0cignY2hlY2tlZCcsIGZhbHNlKTtcbiAgICAgICAgdGhpcy4kZWxcbiAgICAgICAgICAgIC5jc3MoeyBvcGFjaXR5OiAwLjMgfSlcbiAgICAgICAgICAgIC5hbmltYXRlKHsgaGVpZ2h0OiAwIH0sIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMzAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIG1ha2VJbmFjdGl2ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tb2RlbC5tYWtlSW5hY3RpdmUoKTtcbiAgICB9LFxuXG4gICAgc2V0RWRpdE1vZGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5tb2RlbC5zZXQoJ2VkaXQtbW9kZScsIHRydWUpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICByZW1vdmVFZGl0TW9kZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLm1vZGVsLnNldCgnZWRpdC1tb2RlJywgZmFsc2UpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICBzYXZlRWRpdDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB0aGlzLnVwZGF0ZURhdGEoKTtcbiAgICAgICAgdGhpcy53b3JsZHNcbiAgICAgICAgICAgIC51cGRhdGVVc2VyKHRoaXMubW9kZWwpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMucmVtb3ZlRWRpdE1vZGUoKTtcbiAgICAgICAgICAgICAgICBfdGhpcy4kZWwudHJpZ2dlcigndXBkYXRlJywgX3RoaXMpO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGNhbmNlbEVkaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVFZGl0TW9kZSgpO1xuICAgIH0sXG5cbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHRlbXBsID0gdGhpcy5tb2RlbC5nZXQoJ2VkaXQtbW9kZScpID8gdGhpcy5lZGl0VGVtcGxhdGUgOiB0aGlzLnRlbXBsYXRlO1xuICAgICAgICB2YXIgdm0gPSBfLmV4dGVuZCh7XG4gICAgICAgICAgICByb2xlczogdGhpcy5wcm9qZWN0LmdldCgncm9sZXMnKSxcbiAgICAgICAgICAgIG9wdGlvbmFsUm9sZXM6IHRoaXMucHJvamVjdC5nZXQoJ29wdGlvbmFsUm9sZXMnKSxcbiAgICAgICAgICAgIHdvcmxkczogdGhpcy53b3JsZHMuZ2V0V29ybGROYW1lcygpLFxuICAgICAgICAgICAgbmV3V29ybGQ6IHRoaXMud29ybGRzLmdldE5leHRXb3JsZE5hbWUoKVxuICAgICAgICB9LCB0aGlzLm1vZGVsLnRvSlNPTigpKTtcblxuICAgICAgICB0aGlzLiRlbC5odG1sKHRlbXBsKHZtKSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIHVwZGF0ZURhdGE6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdGhpcy4kKCdbZGF0YS1maWVsZF0nKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBlbCA9ICQodGhpcyk7XG4gICAgICAgICAgICB2YXIgZmllbGQgPSBlbC5kYXRhKCdmaWVsZCcpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IGVsLnZhbCgpO1xuXG4gICAgICAgICAgICBfdGhpcy5tb2RlbC5zZXQoZmllbGQsIHZhbCk7XG4gICAgICAgIH0pO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQXNzaWdubWVudFJvdzsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBVc2Vyc0NvbGxlY3Rpb24gPSByZXF1aXJlKCcuL3VzZXJzLWNvbGxlY3Rpb24nKTtcbnZhciBXb3JsZHNDb2xsZWN0aW9uID0gcmVxdWlyZSgnLi93b3JsZHMtY29sbGVjdGlvbicpO1xudmFyIFByb2plY3RNb2RlbCA9IHJlcXVpcmUoJy4vcHJvamVjdC1tb2RlbCcpO1xudmFyIEFzc2lnbmVtbnRSb3cgPSByZXF1aXJlKCcuL2Fzc2lnbm1lbnQtcm93Jyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIEFqYXhRdWV1ZSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvYWpheC1xdWV1ZScpO1xuXG5mdW5jdGlvbiBzZXRFbnZpcm9ubWVudChvcHRpb25zKSB7XG4gICAgZW52LnNldChfLm9taXQob3B0aW9ucywgJ2VsJykpO1xufVxuXG52YXIgQXNzaWdubWVudCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgc2V0RW52aXJvbm1lbnQob3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplKG9wdGlvbnMpO1xufTtcblxuQXNzaWdubWVudC5wcm90b3R5cGUgPSB7XG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLmVsID0gdHlwZW9mIG9wdGlvbnMuZWwgPT09ICdzdHJpbmcnID8gJChvcHRpb25zLmVsKVswXSA6IG9wdGlvbnMuZWw7XG4gICAgICAgIHRoaXMuJGVsID0gJCh0aGlzLmVsKTtcbiAgICAgICAgdGhpcy4kID0gXy5wYXJ0aWFsUmlnaHQoJCwgdGhpcy5lbCk7XG5cbiAgICAgICAgdGhpcy51c2VycyA9IG5ldyBVc2Vyc0NvbGxlY3Rpb24oKTtcbiAgICAgICAgdGhpcy53b3JsZHMgPSBuZXcgV29ybGRzQ29sbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnByb2plY3QgPSBuZXcgUHJvamVjdE1vZGVsKCk7XG5cbiAgICAgICAgXy5iaW5kQWxsKHRoaXMsIFsncmVuZGVyJywgJ3JlbmRlclRhYmxlJywgJ3RvZ2dsZUNvbnRyb2xscycsICdzYXZlRWRpdCcsICdzZWxlY3RBbGwnLCAndXNhc3NpZ25TZWxlY3RlZCcsICdfc2hvd1VwZGF0aW5nJywgJ19oaWRlVXBkYXRpbmcnLCAnYXV0b0Fzc2lnbkFsbCcsICdtYWtlVXNlckluYWN0aXZlJ10pO1xuXG4gICAgICAgIHRoaXMuYmluZEV2ZW50cygpO1xuICAgIH0sXG5cbiAgICBiaW5kRXZlbnRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9uKCd1cGRhdGUnLCAndHInLCB0aGlzLnNhdmVFZGl0KTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2lucHV0OmNoZWNrYm94Om5vdCgjc2VsZWN0LWFsbCknLCB0aGlzLnRvZ2dsZUNvbnRyb2xscyk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICcjc2VsZWN0LWFsbCcsIHRoaXMuc2VsZWN0QWxsKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy51bmFzc2lnbi11c2VyJywgdGhpcy51c2Fzc2lnblNlbGVjdGVkKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy5hdXRvLWFzc2lnbi1hbGwnLCB0aGlzLmF1dG9Bc3NpZ25BbGwpO1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnLm1ha2UtdXNlci1pbmFjdGl2ZScsIHRoaXMubWFrZVVzZXJJbmFjdGl2ZSk7XG4gICAgfSxcblxuICAgIGxvYWQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB2YXIgam9pbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLnNldFVzZXJzQ29sbGVjdGlvbih0aGlzLnVzZXJzKTtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLmpvaW5Vc2VycygpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHJldHVybiAkLndoZW4oXG4gICAgICAgICAgICB0aGlzLndvcmxkcy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy51c2Vycy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy5wcm9qZWN0LmZldGNoKClcbiAgICAgICAgKS50aGVuKGpvaW4pO1xuXG4gICAgfSxcblxuICAgIHNhdmVFZGl0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMud29ybGRzLmZldGNoKClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ29udHJvbHMoKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGF1dG9Bc3NpZ25BbGw6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG4gICAgICAgIHZhciBtYXhVc2VycyA9ICt0aGlzLiQoJyNtYXgtdXNlcnMnKS52YWwoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMud29ybGRzLmF1dG9Bc3NpZ25BbGwoeyBtYXhVc2VyczogbWF4VXNlcnMgfSlcbiAgICAgICAgICAgIC5kb25lKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC5mYWlsKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9LFxuXG4gICAgZ2V0U2VsZWN0ZWRJZHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuJCgndGJvZHkgOmNoZWNrYm94OmNoZWNrZWQnKS5tYXAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICQodGhpcykuZGF0YSgnaWQnKTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGZpbmRSb3dWaWV3czogZnVuY3Rpb24gKGlkcykge1xuICAgICAgICByZXR1cm4gXy5tYXAoaWRzLCBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJvd1ZpZXdzW2lkXTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfSxcblxuICAgIHVuYXNzaWduVXNlcnM6IGZ1bmN0aW9uIChpZHMpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIGZvciBub3cgd2UgbmVlZCB0byBzZXF1ZW5jZSB0aGUgY2FsbHMgdG8gdW5hc3NpZ24gdXNlcnMgZnJvbSB3b3JsZHNcbiAgICAgICAgdmFyIHF1ZXVlID0gbmV3IEFqYXhRdWV1ZSgpO1xuXG4gICAgICAgIF8uZWFjaChpZHMsIGZ1bmN0aW9uICh1c2VySWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyID0gdGhpcy51c2Vycy5nZXRCeUlkKHVzZXJJZCk7XG4gICAgICAgICAgICB1c2VyLnNldCgnd29ybGQnLCAnJyk7XG4gICAgICAgICAgICB1c2VyLnNldCgncm9sZScsICcnKTtcbiAgICAgICAgICAgIHF1ZXVlLmFkZChfLnBhcnRpYWwoXy5iaW5kKHRoaXMud29ybGRzLnVwZGF0ZVVzZXIsIHRoaXMud29ybGRzKSwgdXNlcikpO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIHVzYXNzaWduU2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICB2YXIgaWRzID0gdGhpcy5nZXRTZWxlY3RlZElkcygpO1xuXG4gICAgICAgIHZhciBkb25lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy53b3JsZHMuZmV0Y2goKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9oaWRlVXBkYXRpbmcoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudW5hc3NpZ25Vc2VycyhpZHMpLnRoZW4oZG9uZSk7XG4gICAgfSxcblxuICAgIG1ha2VVc2VySW5hY3RpdmU6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdmFyIGlkcyA9IHRoaXMuZ2V0U2VsZWN0ZWRJZHMoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIG1ha2VVc2Vyc0luYWN0aXZlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJvd3MgPSB0aGlzLmZpbmRSb3dWaWV3cyhpZHMpO1xuICAgICAgICAgICAgLy8gZm9yIG5vdyB3ZSBuZWVkIHRvIHNlcXVlbmNlIHRoZSBjYWxscyB0byBwYXRjaCB0aGUgdXNlcnNcbiAgICAgICAgICAgIC8vIHNpbmNlIHRoZSBBUEkgY2FuIG9ubHkgb3BlcmF0ZSBvbiBvbmUgY2FsbCBwZXIgZ3JvdXAgYXQgYSB0aW1lXG4gICAgICAgICAgICB2YXIgcXVldWUgPSBuZXcgQWpheFF1ZXVlKCk7XG4gICAgICAgICAgICBfLmVhY2gocm93cywgZnVuY3Rpb24gKHZpZXcpIHtcbiAgICAgICAgICAgICAgICB2YXIgdXNlciA9IHZpZXcubW9kZWw7XG4gICAgICAgICAgICAgICAgcXVldWUuYWRkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZpZXcubWFrZUluYWN0aXZlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZXcucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gdGhpcy51bmFzc2lnblVzZXJzKGlkcylcbiAgICAgICAgICAgIC50aGVuKG1ha2VVc2Vyc0luYWN0aXZlKTtcblxuXG4gICAgfSxcblxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiQoJ3RhYmxlIHRib2R5JykuZW1wdHkoKTtcbiAgICAgICAgdGhpcy5yZW5kZXJUYWJsZSgpO1xuICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgIH0sXG5cbiAgICByZW5kZXJUYWJsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJvd1ZpZXdzID0ge307XG4gICAgICAgIHZhciByb3dzID0gW107XG4gICAgICAgIHRoaXMudXNlcnMuZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgQXNzaWduZW1udFJvdyh7IG1vZGVsOiB1LCB3b3JsZHM6IHRoaXMud29ybGRzLCBwcm9qZWN0OiB0aGlzLnByb2plY3QgfSk7XG4gICAgICAgICAgICB0aGlzLnJvd1ZpZXdzW3UuZ2V0KCdpZCcpXSA9IHZpZXc7XG4gICAgICAgICAgICByb3dzLnB1c2godmlldy5yZW5kZXIoKS5lbCk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHRoaXMuJCgndGFibGUgdGJvZHknKS5hcHBlbmQocm93cyk7XG4gICAgfSxcblxuXG4gICAgdXBkYXRlQ29udHJvbHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9sc0ZvclNlbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnVwZGF0ZUF1dG9Bc3NpZ25CdXR0b24oKTtcbiAgICAgICAgdGhpcy51cGRhdGVTdGF0dXMoKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlU3RhdHVzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbmNvbHBsZXRlV29ybGRzID0gdGhpcy53b3JsZHMuZ2V0SW5jb21wbGV0ZVdvcmxkc0NvdW50KCk7XG4gICAgICAgIHZhciB1bmFzc2lnbmVkVXNlcnMgPSB0aGlzLnVzZXJzLmdldFVuYXNzaWduZWRVc2Vyc0NvdW50KCk7XG4gICAgICAgIHZhciB0b3RhbFdvcmxkcyA9IHRoaXMud29ybGRzLnNpemUoKTtcblxuICAgICAgICB2YXIgdXNlcnNUZXh0ID0gdW5hc3NpZ25lZFVzZXJzID8gdW5hc3NpZ25lZFVzZXJzID09PSAxID8gJzEgdXNlciBuZWVkcyBhc3NpZ25tZW50LicgOiB1bmFzc2lnbmVkVXNlcnMgKyAnIHVzZXJzIG5lZWQgYXNzaWdubWVudC4nIDogJ0FsbCB1c2VycyBoYXZlIGJlZW4gYXNzaWduZWQuJztcbiAgICAgICAgdmFyIHdvcmxkc1RleHQgPSAhdG90YWxXb3JsZHMgPyAnTm8gd29ybGRzIGhhdmUgYmVlbiBjcmVhdGVkLicgOiAhaW5jb2xwbGV0ZVdvcmxkcyA/ICdBbGwgd29ybGRzIGFyZSBjb21wbGV0ZS4nIDogaW5jb2xwbGV0ZVdvcmxkcyA9PT0gMSA/ICcxIGluY29tcGxldGUgd29ybGQgbmVlZHMgYXR0ZW50aW9uLicgOiBpbmNvbHBsZXRlV29ybGRzICsgJyBpbmNvbXBsZXRlIHdvcmxkcyBuZWVkIGF0dGVudGlvbi4nO1xuXG4gICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cyAudGV4dCcpLnRleHQodXNlcnNUZXh0KTtcbiAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cyAudGV4dCcpLnRleHQod29ybGRzVGV4dCk7XG5cbiAgICAgICAgaWYgKHVuYXNzaWduZWRVc2Vycykge1xuICAgICAgICAgICAgdGhpcy4kKCcjdXNlcnMtc3RhdHVzJykuYWRkQ2xhc3MoJ2luY29tcGxldGUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5jb2xwbGV0ZVdvcmxkcyB8fCAhdG90YWxXb3JsZHMpIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3dvcmxkcy1zdGF0dXMnKS5hZGRDbGFzcygnaW5jb21wbGV0ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLiQoJy5zdGF0dXMtd2lkZ2V0JykuYWRkQ2xhc3MoJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQ29udHJvbHNGb3JTZWxlY3Rpb246IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG51bVNlbGVjdGVkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpLmxlbmd0aDtcbiAgICAgICAgdGhpcy4kKCcuY29tcG9uZW50LmNvbnRyb2xzJylbbnVtU2VsZWN0ZWQgPyAnYWRkQ2xhc3MnIDogJ3JlbW92ZUNsYXNzJ10oJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQXV0b0Fzc2lnbkJ1dHRvbjogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIGlmICh0aGlzLnByb2plY3QuaXNEeW5hbWljQXNzaWdubWVudCgpKSB7XG4gICAgICAgICAgICB2YXIgaGFzUm9sZXMgPSB0aGlzLnByb2plY3QuaGFzUm9sZXMoKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5zaW5nbGUnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYycpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5keW5hbWljLW5vLXJvbGVzLXRleHQnKVtoYXNSb2xlcyA/ICdoaWRlJyA6ICdzaG93J10oKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpW2hhc1JvbGVzID8gJ2hpZGUnIDogJ3Nob3cnXSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLmR5bmFtaWMnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYy1uby1yb2xlcy10ZXh0JykuaGlkZSgpO1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLnNpbmdsZScpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpLnNob3coKTtcblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudXNlcnMuYWxsVXNlcnNBc3NpZ25lZCgpKSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLnJlbW92ZUNsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLmFkZENsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc2VsZWN0QWxsOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICB0aGlzLiQoJ3Rib2R5IDpjaGVja2JveCcpLnByb3AoJ2NoZWNrZWQnLCBlLnRhcmdldC5jaGVja2VkKTtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICB0b2dnbGVDb250cm9sbHM6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB0b3RhbCA9IHRoaXMuJCgndGJvZHkgOmNoZWNrYm94Jyk7XG4gICAgICAgIHZhciBjaGVja2VkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpO1xuXG4gICAgICAgIGlmICh0b3RhbC5sZW5ndGggPT09IGNoZWNrZWQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykuYXR0cignY2hlY2tlZCcsICdjaGVja2VkJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykucmVtb3ZlQXR0cignY2hlY2tlZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICBfc2hvd1VwZGF0aW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLmNzcyh7IG9wYWNpdHk6IDAuNCB9KTtcbiAgICB9LFxuXG4gICAgX2hpZGVVcGRhdGluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5jc3MoeyBvcGFjaXR5OiAxIH0pO1xuICAgIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBc3NpZ25tZW50OyIsIid1c2Ugc3RyaWN0JztcblxudmFyIEJhc2VDb2xsZWN0aW9uID0gZnVuY3Rpb24gKG1vZGVscywgb3B0aW9ucykge1xuICAgIHRoaXMuX21vZGVscyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlQ29sbGVjdGlvbi5wcm90b3R5cGUsIHtcbiAgICBpZEF0dHJpYnV0ZTogJ2lkJyxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uIChtb2RlbHMsIG9wdGlvbnMpIHtcbiAgICB9LFxuXG4gICAgY3JlYXRlOiBmdW5jdGlvbiAoYXR0ciwgb3B0aW9ucykge1xuICAgICAgICB2YXIgbSA9IG5ldyB0aGlzLm1vZGVsKGF0dHIsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnNldChtKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAobW9kZWxzLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMuX21vZGVscy5sZW5ndGggPSAwO1xuICAgICAgICB0aGlzLnNldChtb2RlbHMpO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uIChtb2RlbCkge1xuICAgICAgICBfLnJlbW92ZSh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbSA9PT0gbW9kZWw7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGRlbGV0ZSBtb2RlbC5jb2xsZWN0aW9uO1xuXG4gICAgICAgIHJldHVybiBtb2RlbDtcbiAgICB9LFxuXG4gICAgc2V0OiBmdW5jdGlvbiAobW9kZWxzKSB7XG4gICAgICAgIGlmICghbW9kZWxzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBtb2RlbHMgPSBbXS5jb25jYXQobW9kZWxzKTtcblxuICAgICAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIF8uZWFjaChtb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICBpZiAoIShtIGluc3RhbmNlb2YgdGhpcy5tb2RlbCkpIHtcbiAgICAgICAgICAgICAgICBtID0gbmV3IHRoaXMubW9kZWwobSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG0uY29sbGVjdGlvbiA9IHRoaXM7XG5cbiAgICAgICAgICAgIHRoaXMuX21vZGVscy5wdXNoKG0pO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICB0aGlzLnNvcnQuY2FsbCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gbW9kZWxzO1xuICAgIH0sXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBiLl9kYXRhW3RoaXMuaWRBdHRyaWJ1dGVdIC0gYS5fZGF0YVt0aGlzLmlkQXR0cmlidXRlXTtcbiAgICB9LFxuXG4gICAgc29ydDogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLl9tb2RlbHMgPSB0aGlzLl9tb2RlbHMuc29ydCh0aGlzLnNvcnRGbi5iaW5kKHRoaXMpKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzO1xuICAgIH0sXG5cbiAgICBnZXRCeUlkOiBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgcmV0dXJuIF8uZmluZCh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbS5nZXQodGhpcy5pZEF0dHJpYnV0ZSkgPT09IGlkO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgZWFjaDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uZWFjaCh0aGlzLl9tb2RlbHMsIGNiLCBjdHggfHwgdGhpcyk7XG4gICAgfSxcblxuICAgIGFsbDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uYWxsKHRoaXMuX21vZGVscywgY2IsIGN0eCB8fCB0aGlzKTtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBfLmludm9rZSh0aGlzLl9tb2RlbHMsICd0b0pTT04nKTtcbiAgICB9LFxuXG4gICAgZmluZDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbmQodGhpcy5fbW9kZWxzLCBmbik7XG4gICAgfSxcblxuICAgIGZpbHRlcjogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbHRlcih0aGlzLl9tb2RlbHMsIGZuKTtcbiAgICB9LFxuXG4gICAgc2l6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgbWFwOiBmdW5jdGlvbiAoZm4sIGN0eCkge1xuICAgICAgICByZXR1cm4gXy5tYXAodGhpcy5fbW9kZWxzLCBmdW5jdGlvbiAobW9kZWwpIHtcbiAgICAgICAgICAgIHJldHVybiBmbi5jYWxsKGN0eCwgbW9kZWwudG9KU09OKCkpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgcGx1Y2s6IGZ1bmN0aW9uIChmaWVsZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBtW2ZpZWxkXTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlQ29sbGVjdGlvbjsiLCIndXNlIHN0cmljdCc7XG5cblxudmFyIEJhc2VNb2RlbCA9IGZ1bmN0aW9uIChhdHRyLCBvcHRpb25zKSB7XG4gICAgYXR0ciA9IF8uZGVmYXVsdHMoe30sIGF0dHIsIF8ucmVzdWx0KHRoaXMsICdkZWZhdWx0cycpKTtcbiAgICB0aGlzLl9kYXRhID0ge307XG4gICAgdGhpcy5zZXQoYXR0ciwgb3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlTW9kZWwucHJvdG90eXBlLCB7XG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKGF0dHIsIG9wdGlvbnMpIHtcblxuICAgIH0sXG5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbCwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChrZXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWw7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBfLmV4dGVuZCh0aGlzLl9kYXRhLCBhdHRycyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGdldDogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YVtrZXldO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jb2xsZWN0aW9uLnJlbW92ZSh0aGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICB0b0pTT046IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGE7XG4gICAgfSxcblxuICAgIHBpY2s6IGZ1bmN0aW9uIChrZXlzKSB7XG4gICAgICAgIHJldHVybiBfLnBpY2sodGhpcy5fZGF0YSwga2V5cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlTW9kZWw7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZW52ID0ge1xuICAgIGFjY291bnQ6ICcnLFxuICAgIHByb2plY3Q6ICcnLFxuICAgIGdyb3VwOiAnJyxcbiAgICBncm91cElkOiAnJyxcbiAgICB0b2tlbjogJycsXG4gICAgc2VydmVyOiB7XG4gICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgcHJvdG9jb2w6ICdodHRwcydcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBzZXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGVudiA9IF8ubWVyZ2UoZW52LCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBlbnY7XG4gICAgfVxufTsiLCIoZnVuY3Rpb24gKCkge1xuICAgICd1c2Ugc3RyaWN0JztcbiAgICB2YXIgQXBwID0gcmVxdWlyZSgnLi9hc3NpZ25tZW50LmpzJyk7XG5cbiAgICB3aW5kb3cuZm9yaW8gPSB3aW5kb3cuZm9yaW8gfHwge307XG4gICAgd2luZG93LmZvcmlvLk11bHRpcGxheWVyQXNzaWdubWVudENvbXBvbmVudCA9IEFwcDtcbn0pKCk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBzZXJ2aWNlTG9jYXRvciA9IHJlcXVpcmUoJy4vc2VydmljZS1sb2NhdG9yJyk7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG4vLyB2YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBpc0R5bmFtaWNBc3NpZ25tZW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldCgnd29ybGRzJykgPT09ICdkeW5hbWljJztcbiAgICB9LFxuXG4gICAgaGFzUm9sZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJvbGVzID0gdGhpcy5nZXQoJ3JvbGVzJyk7XG4gICAgICAgIHJldHVybiByb2xlcyAmJiAhIXJvbGVzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGFwaSA9IHNlcnZpY2VMb2NhdG9yLndvcmxkQXBpKCk7XG5cbiAgICAgICAgcmV0dXJuIGFwaS5nZXRQcm9qZWN0U2V0dGluZ3MoKS50aGVuKGZ1bmN0aW9uIChzZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5zZXQoc2V0dGluZ3MpO1xuICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cbn0pOyIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVudiA9IHJlcXVpcmUoJy4vZGVmYXVsdHMuanMnKTtcblxudmFyIGNhY2hlID0ge307XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHdvcmxkQXBpOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghY2FjaGUud29ybGRBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLndvcmxkQXBpID0gbmV3IEYuc2VydmljZS5Xb3JsZChlbnYuZ2V0KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLndvcmxkQXBpO1xuICAgIH0sXG5cbiAgICBtZW1iZXJBcGk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFjYWNoZS5tZW1iZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLm1lbWJlckFwaSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKF8ucGljayhlbnYuZ2V0KCksIFsnZ3JvdXBJZCcsICdzZXJ2ZXInXSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLm1lbWJlckFwaTtcbiAgICB9LFxuXG4gICAgdXNlckFwaTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIWNhY2hlLnVzZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLnVzZXJBcGkgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoXy5waWNrKGVudi5nZXQoKSwgWydhY2NvdW50JywgJ3NlcnZlciddKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2FjaGUudXNlckFwaTtcbiAgICB9XG59OyIsImV4cG9ydHNbXCJlZGl0LXVzZXItcm93XCJdID0gZnVuY3Rpb24ob2JqKSB7XG5vYmogfHwgKG9iaiA9IHt9KTtcbnZhciBfX3QsIF9fcCA9ICcnLCBfX2UgPSBfLmVzY2FwZSwgX19qID0gQXJyYXkucHJvdG90eXBlLmpvaW47XG5mdW5jdGlvbiBwcmludCgpIHsgX19wICs9IF9fai5jYWxsKGFyZ3VtZW50cywgJycpIH1cbndpdGggKG9iaikge1xuX19wICs9ICc8dGQ+PGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGNsYXNzPVwic2VsZWN0XCIgZGF0YS1pZD1cIicgK1xuKChfX3QgPSAoIGlkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+PC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cIndvcmxkc1wiIGNsYXNzPVwiZm9ybS1jb250cm9sXCIgZGF0YS1maWVsZD1cIndvcmxkXCI+XFxuXFxuICAgICc7XG4gXy5lYWNoKHdvcmxkcywgZnVuY3Rpb24gKHcpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHcgPT09IHdvcmxkID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIicgK1xuKChfX3QgPSAoIG5ld1dvcmxkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiIGNsYXNzPVwibmV3LXdvcmxkLXRleHRcIj48aT4nICtcbigoX190ID0gKCBuZXdXb3JsZCApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbicgLSBOZXcgLTwvaT48L29wdGlvbj5cXG4gICAgPC9zZWxlY3Q+XFxuPC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cInJvbGVzXCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBkYXRhLWZpZWxkPVwicm9sZVwiPlxcbiAgICAnO1xuIF8uZWFjaChyb2xlcywgZnVuY3Rpb24gKHIpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHIgPT09IHJvbGUgPyAnc2VsZWN0ZWQnIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPicgK1xuKChfX3QgPSAoIHIgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC9vcHRpb24+XFxuICAgICc7XG4gfSk7IDtcbl9fcCArPSAnXFxuXFxuICAgICc7XG4gXy5lYWNoKG9wdGlvbmFsUm9sZXMsIGZ1bmN0aW9uIChyKSB7IDtcbl9fcCArPSAnXFxuICAgICAgICA8b3B0aW9uIHZhbHVlPVwiJyArXG4oKF9fdCA9ICggciApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbidcIiAnICtcbigoX190ID0gKCByID09PSByb2xlID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJyA8aT4oT3B0aW9uYWwpPC9pPjwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICA8L3NlbGVjdD5cXG48L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi10b29scyBidG4tc2F2ZSBzYXZlXCI+U2F2ZTwvYnV0dG9uPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi10b29scyBidG4tY2FuY2VsIGNhbmNlbFwiPkNhbmNlbDwvYnV0dG9uPlxcbjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTtcbmV4cG9ydHNbXCJ1c2VyLXJvd1wiXSA9IGZ1bmN0aW9uKG9iaikge1xub2JqIHx8IChvYmogPSB7fSk7XG52YXIgX190LCBfX3AgPSAnJywgX19lID0gXy5lc2NhcGU7XG53aXRoIChvYmopIHtcbl9fcCArPSAnPHRkPjxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cInNlbGVjdFwiIGRhdGEtaWQ9XCInICtcbigoX190ID0gKCBpZCkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggIWlzV29ybGRDb21wbGV0ZSA/ICc8ZW0gY2xhc3M9XCJmLWljb24gZi13YXJuaW5nXCI+PC9lbT4nIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggd29ybGQgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggcm9sZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPjxidXR0b24gY2xhc3M9XCJidG4gZWRpdCBidG4tZWRpdCBidG4tdG9vbHMgYXV0by1oaWRlXCI+RWRpdDwvYnV0dG9uPjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBkZWZhdWx0czoge1xuICAgICAgICB3b3JsZDogJycsXG4gICAgICAgIHJvbGU6ICcnLFxuICAgICAgICBhY3RpdmU6IHRydWUsXG4gICAgICAgIGlzV29ybGRDb21wbGV0ZTogdHJ1ZSxcbiAgICAgICAgZmlyc3ROYW1lOiAnJyxcbiAgICAgICAgbGFzdE5hbWU6ICcnXG4gICAgfSxcblxuICAgIG1ha2VBY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gbWVtYmVyQXBpLm1ha2VVc2VyQWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBtYWtlSW5hY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBmYWxzZSk7XG5cbiAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5tYWtlVXNlckluYWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cblxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcblxudmFyIE1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcblxuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBtb2RlbDogTW9kZWwsXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHZhciBhdyA9IGEuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBidyA9IGIuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIGlmIChhdyAhPT0gYncpIHtcbiAgICAgICAgICAgIHJldHVybiBhdyA8IGJ3ID8gLTEgOiAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGIuZ2V0KCd1c2VyTmFtZScpID4gYS5nZXQoJ3VzZXJOYW1lJykgPyAtMSA6IDE7XG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJC5hamF4U2V0dXAoe1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIGVudi5nZXQoKS50b2tlblxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgYWxsVXNlcnNBc3NpZ25lZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hbGwoZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiAhIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0VW5hc3NpZ25lZFVzZXJzQ291bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmlsdGVyKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICByZXR1cm4gIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KS5sZW5ndGg7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBncm91cElkID0gZW52LmdldCgpLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGdldEdyb3VwVXNlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbWVtYmVyQXBpID0gc2VydmljZUxvY2F0b3IubWVtYmVyQXBpKCk7XG4gICAgICAgICAgICB2YXIgdXNlckFwaSA9IHNlcnZpY2VMb2NhdG9yLnVzZXJBcGkoKTtcblxuICAgICAgICAgICAgdmFyIGxvYWRHcm91cE1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5nZXRHcm91cERldGFpbHMoKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBsb2FkVXNlcnNJbmZvID0gZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vbkZhY0FuZEFjdGl2ZSA9IGZ1bmN0aW9uICh1KSB7IHJldHVybiB1LmFjdGl2ZSAmJiB1LnJvbGUgIT09ICdmYWNpbGl0YXRvcic7IH07XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJzID0gXy5wbHVjayhfLmZpbHRlcihncm91cC5tZW1iZXJzLCBub25GYWNBbmRBY3RpdmUpLCAndXNlcklkJyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVzZXJBcGkuZ2V0KHsgaWQ6IHVzZXJzIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGxvYWRHcm91cE1lbWJlcnMoKVxuICAgICAgICAgICAgICAgIC50aGVuKGxvYWRVc2Vyc0luZm8pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgZ2V0R3JvdXBVc2VycygpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAodXNlcnMpIHtcbiAgICAgICAgICAgICAgICB1c2VycyA9IF8ubWFwKHVzZXJzLCBmdW5jdGlvbiAodSkgeyByZXR1cm4gXy5leHRlbmQodSwgeyBncm91cElkOiBncm91cElkIH0pOyB9KTtcbiAgICAgICAgICAgICAgICBfdGhpcy5zZXQodXNlcnMpO1xuICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHVzZXJzLCBfdGhpcyk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9XG5cbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBkZWZhdWx0czoge1xuICAgICAgICB1c2VyczogbnVsbCxcbiAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX19zdXBlci5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgdGhpcy5fZGF0YS51c2VycyA9IHRoaXMuX2RhdGEudXNlcnMgfHwgW107XG5cbiAgICAgICAgdGhpcy5fd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuXG4gICAgICAgIHZhciBpZCA9IHRoaXMuZ2V0KCdpZCcpO1xuICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgYWRkVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIHVzZXJzLnB1c2godXNlcik7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuc2F2ZSgpO1xuICAgIH0sXG5cbiAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlcikge1xuICAgICAgICB2YXIgaWQgPSB0aGlzLmdldCgnaWQnKTtcbiAgICAgICAgdmFyIGNoZWNrV29ybGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuZ2V0KCd1c2VycycpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSkuZGVsZXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICBfLnJlbW92ZSh0aGlzLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiB1LmdldCgnaWQnKSA9PT0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl93b3JsZEFwaVxuICAgICAgICAgICAgLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSlcbiAgICAgICAgICAgIC5yZW1vdmVVc2VyKHsgdXNlcklkOiB1c2VyLmdldCgnaWQnKSB9KVxuICAgICAgICAgICAgLnRoZW4oY2hlY2tXb3JsZCk7XG4gICAgfSxcblxuICAgIHNhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIG1hcFVzZXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIF8ubWFwKHRoaXMuZ2V0KCd1c2VycycpLCBmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgICAgIHZhciByZXMgPSB7IHVzZXJJZDogdS5nZXQoJ2lkJykgfTtcbiAgICAgICAgICAgICAgICB2YXIgcm9sZSA9IHUuZ2V0KCdyb2xlJyk7XG5cbiAgICAgICAgICAgICAgICBpZiAocm9sZSkge1xuICAgICAgICAgICAgICAgICAgICByZXMucm9sZSA9IHJvbGU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIGNyZWF0ZVdvcmxkID0gXy5wYXJ0aWFsKHRoaXMuX3dvcmxkQXBpLmNyZWF0ZSwgdGhpcy5waWNrKFsnbW9kZWwnLCAnbmFtZScsICdtaW5Vc2VycyddKSk7XG4gICAgICAgIHZhciBhZGRVc2VycyA9IF8ucGFydGlhbChfdGhpcy5fd29ybGRBcGkuYWRkVXNlcnMsIG1hcFVzZXJzKCksIHsgZmlsdGVyOiBfdGhpcy5nZXQoJ2lkJykgfSk7XG4gICAgICAgIHZhciBzYXZlZFVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIGlmICh0aGlzLmlzTmV3KCkpIHtcbiAgICAgICAgICAgIC8vIHdlIG5lZWQgdG8gY3JlYXRlIHRoZSB3b3JsZCBpbiB0aGUgQVBJIGFuZCB0aGVuIGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVXb3JsZCgpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNldCh3b3JsZCk7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLl93b3JsZEFwaS51cGRhdGVDb25maWcoeyBmaWx0ZXI6IHdvcmxkLmlkIH0pO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oYWRkVXNlcnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHVzZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHNpbmNlIHdlIHJlLXNldCB0aGUgd29ybGQsIHJlLXNldCB0aGUgdXNlcnNcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuc2V0KCd1c2VycycsIHNhdmVkVXNlcnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gdGhlIHdvcmxkIGlzIGFscmVhZHkgY3JlYXRlZCBqdXN0IGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBhZGRVc2VycygpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGlzTmV3OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5nZXQoJ2xhc3RNb2RpZmllZCcpO1xuICAgIH1cblxufSk7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgTW9kZWwgPSByZXF1aXJlKCcuL3dvcmxkLW1vZGVsJyk7XG52YXIgVXNlck1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG52YXIgZG9uZUZuID0gZnVuY3Rpb24gKGR0ZCwgYWZ0ZXIpIHtcbiAgICByZXR1cm4gXy5hZnRlcihhZnRlciwgZHRkLnJlc29sdmUpO1xufTtcblxudmFyIHdvcmxkQXBpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgbW9kZWw6IE1vZGVsLFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBfX3N1cGVyLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuICAgIH0sXG5cbiAgICBhdXRvQXNzaWduQWxsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gd29ybGRBcGkuYXV0b0Fzc2lnbihvcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzZXQodGhpcy5wYXJzZSh3b3JsZHMpKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGdldEluY29tcGxldGVXb3JsZHNDb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24gKHcpIHtcbiAgICAgICAgICAgIHJldHVybiAhdy5nZXQoJ2NvbXBsZXRlJyk7XG4gICAgICAgIH0pLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgdXBkYXRlVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHdvcmxkTmFtZSA9IHVzZXIuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgcHJldldvcmxkID0gdGhpcy5nZXRXb3JsZEJ5VXNlcih1c2VyKTtcbiAgICAgICAgdmFyIGN1cldvcmxkID0gdGhpcy5nZXRPckNyZWF0ZVdvcmxkKHdvcmxkTmFtZSk7XG4gICAgICAgIHZhciBkb25lID0gZG9uZUZuKGR0ZCwgMSk7XG5cbiAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUncyBhbnl0aGluZyB0byBkb1xuICAgICAgICBpZiAoIXByZXZXb3JsZCAmJiAhY3VyV29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiBkdGQucmVzb2x2ZSgpLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwcmV2V29ybGQpIHtcbiAgICAgICAgICAgIHByZXZXb3JsZC5yZW1vdmVVc2VyKHVzZXIpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY3VyV29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjdXJXb3JsZC5hZGRVc2VyKHVzZXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAudGhlbihkb25lKTtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJXb3JsZCkge1xuICAgICAgICAgICAgY3VyV29ybGQuYWRkVXNlcih1c2VyKVxuICAgICAgICAgICAgICAgIC50aGVuKGRvbmUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldE9yQ3JlYXRlV29ybGQ6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgaWYgKCF3b3JsZE5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB3b3JsZCA9IHRoaXMuZ2V0V29yZEJ5TmFtZSh3b3JsZE5hbWUpO1xuXG4gICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgIHdvcmxkID0gdGhpcy5jcmVhdGUoeyBuYW1lOiB3b3JsZE5hbWUgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gd29ybGQ7XG4gICAgfSxcblxuICAgIGdldFdvcmRCeU5hbWU6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmluZChmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiB3b3JsZC5nZXQoJ25hbWUnKSA9PT0gd29ybGROYW1lO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGRCeVVzZXI6IGZ1bmN0aW9uICh1c2VyKSB7XG4gICAgICAgIGlmICghdXNlci5nZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZ2V0V29ybGRCeVVzZXIgZXhwZWN0ZXMgYSBtb2RlbCAoJyArIHVzZXIgKyAnKScpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGlkID0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFdvcmxkQnlVc2VySWQoaWQpO1xuICAgIH0sXG5cbiAgICBnZXRXb3JsZEJ5VXNlcklkOiBmdW5jdGlvbiAodXNlcklkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZpbmQoZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICByZXR1cm4gXy5maW5kKHdvcmxkLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdS5nZXQoJ2lkJykgPT09IHVzZXJJZDtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGROYW1lczogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wbHVjaygnbmFtZScpO1xuICAgIH0sXG5cbiAgICBnZXROZXh0V29ybGROYW1lOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBwYWQgPSBmdW5jdGlvbiAobnVtLCBwbGFjZXMpIHtcbiAgICAgICAgICAgIHZhciB6ZXJvcyA9ICcwMDAwMDAwMDAwMDAwMDAwMDAnO1xuICAgICAgICAgICAgdmFyIGRpZ2l0cyA9IG51bS50b1N0cmluZygpLmxlbmd0aDtcbiAgICAgICAgICAgIHZhciBuZWVkZWQgPSBwbGFjZXMgLSBkaWdpdHM7XG4gICAgICAgICAgICByZXR1cm4gemVyb3Muc3Vic3RyKDAsIG5lZWRlZCkgKyBudW07XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHdvcmxkcyA9IHRoaXMuZ2V0V29ybGROYW1lcygpO1xuXG4gICAgICAgIGlmICghd29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuICdXb3JsZDAwMSc7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcHJvcGVyTmFtZXMgPSBfLmZpbHRlcih3b3JsZHMsIGZ1bmN0aW9uICh3KSB7IHJldHVybiAvV29ybGRcXGRcXGRcXGQvLnRlc3Qodyk7IH0pLnNvcnQoKTtcbiAgICAgICAgdmFyIGxhc3RXb3JsZCA9IHByb3Blck5hbWVzW3Byb3Blck5hbWVzLmxlbmd0aCAtIDFdO1xuICAgICAgICB2YXIgbnVtV29ybGQgPSArbGFzdFdvcmxkLm1hdGNoKC9Xb3JsZChcXGRcXGRcXGQpLylbMV07XG4gICAgICAgIHJldHVybiAnV29ybGQnICsgcGFkKG51bVdvcmxkICsgMSwgMyk7XG4gICAgfSxcblxuICAgIHNldFVzZXJzQ29sbGVjdGlvbjogZnVuY3Rpb24gKHVzZXJzQ29sbGVjdGlvbikge1xuICAgICAgICB0aGlzLnVzZXJzQ29sbGVjdGlvbiA9IHVzZXJzQ29sbGVjdGlvbjtcbiAgICB9LFxuXG4gICAgam9pblVzZXJzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1c2Vyc0hhc2ggPSB7fTtcbiAgICAgICAgdmFyIHVzZXJzQ29sbGVjdGlvbiA9IHRoaXMudXNlcnNDb2xsZWN0aW9uO1xuICAgICAgICB1c2Vyc0NvbGxlY3Rpb24uZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdS5zZXQoeyBpc1dvcmxkQ29tcGxldGU6IHRydWUgfSk7XG4gICAgICAgICAgICByZXR1cm4gKHVzZXJzSGFzaFt1LmdldCgnaWQnKV0gPSB1KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5lYWNoKGZ1bmN0aW9uICh3LCBpKSB7XG4gICAgICAgICAgICB2YXIgbmFtZSA9IHcuZ2V0KCduYW1lJyk7XG4gICAgICAgICAgICB2YXIgaXNDb21wbGV0ZSA9IHcuZ2V0KCdjb21wbGV0ZScpO1xuICAgICAgICAgICAgdy5zZXQoeyBpbmRleDogaSwgbmFtZTogbmFtZSB8fCAoaSArIDEpICsgJycgfSk7XG4gICAgICAgICAgICBfLmVhY2gody5nZXQoJ3VzZXJzJyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgaWYgKHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldKSB7XG4gICAgICAgICAgICAgICAgICAgIHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldLnNldCh7IHdvcmxkOiBuYW1lLCByb2xlOiB1LmdldCgncm9sZScpLCBpc1dvcmxkQ29tcGxldGU6IGlzQ29tcGxldGUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHVzZXJzQ29sbGVjdGlvbi5zb3J0KCk7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB3b3JsZEFwaS5saXN0KClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc2V0KHRoaXMucGFyc2Uod29ybGRzKSk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBwYXJzZTogZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICBpZiAod29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgd29ybGRzID0gXy5tYXAod29ybGRzLCBmdW5jdGlvbiAodykge1xuICAgICAgICAgICAgICAgIHZhciB1c2VycyA9IF8ubWFwKHcudXNlcnMsIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGluIHRoZSB3b3JsZCBhcGkgdXNlcnMgSWRzIGNvbWVzIGFzIHVzZXJJZFxuICAgICAgICAgICAgICAgICAgICAvLyBtYWtlIHN1cmUgd2UgYWRkIGl0IGFzIGlkIHNvIHdlIGNhbiB1c2UgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIHNhbWUgY29kZSB0byBhY2Nlc3MgbW9kZWxzIHRoYXQgY29tZSBmcm9tIHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyBtZW1iZXIvbG9jYWwgYXBpIGFzIHdpdGggdGhlIHdvcmxkIGFwaVxuICAgICAgICAgICAgICAgICAgICB1LmlkID0gdS51c2VySWQ7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVXNlck1vZGVsKHUpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgdy51c2VycyA9IHVzZXJzO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHc7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB3b3JsZHM7XG4gICAgfVxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuKiBVdGlsaXR5IGNsYXNzIHRvIG1ha2UgYWpheCBjYWxscyBzZXF1ZW5jaWFsXG4qL1xuZnVuY3Rpb24gQWpheFF1ZXVlICgpIHtcbiAgICB0aGlzLnF1ZXVlID0gW107XG59XG5cbiQuZXh0ZW5kKEFqYXhRdWV1ZS5wcm90b3R5cGUsIHtcbiAgICBhZGQ6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICByZXR1cm4gdGhpcy5xdWV1ZS5wdXNoKGZuKTtcbiAgICB9LFxuXG4gICAgZXhlY3V0ZTogZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgY29udGV4dCA9IGNvbnRleHQgfHwgdGhpcztcblxuICAgICAgICBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgICAgICAgaWYgKF90aGlzLnF1ZXVlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBmbiA9IF90aGlzLnF1ZXVlLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgICAgICBmbi5jYWxsKGNvbnRleHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKG5leHQpXG4gICAgICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbmV4dCgpO1xuXG4gICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQWpheFF1ZXVlOyIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiJdfQ== diff --git a/dist/epicenter.js b/dist/epicenter.js index df5e4ff3..a41dc3f0 100644 --- a/dist/epicenter.js +++ b/dist/epicenter.js @@ -1922,7 +1922,7 @@ var store; var token; var session; -function saveSession(userInfo) { +function saveSession(userInfo, store) { var serialized = JSON.stringify(userInfo); store.set(EPI_SESSION_KEY, serialized); @@ -1931,7 +1931,7 @@ function saveSession(userInfo) { store.set(EPI_COOKIE_KEY, userInfo.auth_token); } -function getSession() { +function getSession(store) { var session = store.get(EPI_SESSION_KEY) || '{}'; return JSON.parse(session); } @@ -1949,9 +1949,13 @@ function AuthManager(options) { this.options.project = urlConfig.projectPath; } - store = new StorageFactory(this.options.store); - session = getSession(); - token = store.get(EPI_COOKIE_KEY) || ''; + if (this.options.store.root === undefined && this.options.account && this.options.project) { + this.options.store.root = '/app/' + this.options.account + '/' + this.options.project; + } + + this.store = new StorageFactory(this.options.store); + session = getSession(this.store); + token = this.store.get(EPI_COOKIE_KEY) || ''; //jshint camelcase: false //jscs:disable this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token }); @@ -1977,9 +1981,9 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * * authMgr.login({ * account: 'acme-simulations', - * project: 'supply-chain-game', + * project: 'supply-chain-game', * userName: 'enduser1', - * password: 'passw0rd' + * password: 'passw0rd' * }) * .then(function(statusObj) { * // if enduser1 belongs to exactly one group @@ -1987,8 +1991,8 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * // continue here * }) * .fail(function(statusObj) { - * // if enduser1 belongs to multiple groups, - * // the login() call fails + * // if enduser1 belongs to multiple groups, + * // the login() call fails * // and returns all groups of which the user is a member * for (var i=0; i < statusObj.userGroups.length; i++) { * console.log(statusObj.userGroups[i].name, statusObj.userGroups[i].groupId); @@ -1997,12 +2001,12 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * * **Parameters** * - * @param {Object} `options` (Optional) Overrides for configuration options. If not passed in when creating an instance of the manager (`F.manager.AuthManager()`), these options should include: + * @param {Object} `options` (Optional) Overrides for configuration options. If not passed in when creating an instance of the manager (`F.manager.AuthManager()`), these options should include: * @param {string} `options.account` The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). * @param {string} `options.userName` Email or username to use for logging in. * @param {string} `options.password` Password for specified `userName`. * @param {string} `options.project` (Optional) The **Project ID** for the project to log this user into. - * @param {string} `options.groupId` The id of the group to which `userName` belongs. Required for [end users](../../../glossary/#users) if the `project` is specified and if the end users are members of multiple [groups](../../../glossary/#groups), otherwise optional. + * @param {string} `options.groupId` The id of the group to which `userName` belongs. Required for [end users](../../../glossary/#users) if the `project` is specified and if the end users are members of multiple [groups](../../../glossary/#groups), otherwise optional. */ login: function (options) { var _this = this; @@ -2035,7 +2039,6 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { //jshint camelcase: false //jscs:disable token = response.access_token; - var userInfo = decodeToken(token); var userGroupOpts = $.extend(true, {}, adapterOptions, { success: $.noop, token: token }); _this.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts).done( function (memberInfo) { @@ -2049,7 +2052,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { }; // The group is not required if the user is not logging into a project if (!adapterOptions.project) { - saveSession(sessionInfo); + saveSession(sessionInfo, _this.store); outSuccess.apply(this, [data]); $d.resolve(data); return; @@ -2079,7 +2082,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { 'groupName': group.name, 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator' }); - saveSession(sessionInfoWithGroup); + saveSession(sessionInfoWithGroup, _this.store); outSuccess.apply(this, [data]); $d.resolve(data); } else { @@ -2139,8 +2142,8 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * **Example** * * authMgr.getToken() - * .then(function (token) { - * console.log('My token is ', token); + * .then(function (token) { + * console.log('My token is ', token); * }); * * **Parameters** @@ -2168,8 +2171,8 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * // get groups for current user * var sessionObj = authMgr.getCurrentUserSessionInfo(); * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token }) - * .then(function (groups) { - * for (var i=0; i < groups.length; i++) + * .then(function (groups) { + * for (var i=0; i < groups.length; i++) * { console.log(groups[i].name); } * }); * @@ -2209,7 +2212,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed. * - * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option. + * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option. * * **Example** * @@ -2219,7 +2222,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * @param {Object} `options` (Optional) Overrides for configuration options. */ getCurrentUserSessionInfo: function (options) { - return getSession(options); + return getSession(this.store, options); } }); @@ -6722,7 +6725,7 @@ module.exports = function (config) { domain: '.forio.com' }; - var serviceOptions = $.extend({}, defaults, config); + this.serviceOptions = $.extend({}, defaults, config); var publicAPI = { // * TBD @@ -6755,7 +6758,7 @@ module.exports = function (config) { * cs.set({ name:'smith', age:'32' }); */ set: function (key, value, options) { - var setOptions = $.extend(true, {}, serviceOptions, options); + var setOptions = $.extend(true, {}, this.serviceOptions, options); var domain = setOptions.domain; var path = setOptions.root; @@ -6792,7 +6795,7 @@ module.exports = function (config) { * cs.remove('person'); */ remove: function (key, options) { - var remOptions = $.extend(true, {}, serviceOptions, options); + var remOptions = $.extend(true, {}, this.serviceOptions, options); var domain = remOptions.domain; var path = remOptions.root; @@ -7443,4 +7446,4 @@ module.exports = (function () { }()); },{"./query-util":44}]},{},[6]) -//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL25vZGVfbW9kdWxlcy9pZWVlNzU0L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvaXMtYXJyYXkvaW5kZXguanMiLCJzcmMvYXBpLXZlcnNpb24uanNvbiIsInNyYy9hcHAuanMiLCJzcmMvbWFuYWdlcnMvYXV0aC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2NoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2tleS1uYW1lcy5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9hbHdheXMtbmV3LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2lkZW50aXR5LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL211bHRpcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcC5qcyIsInNyYy9tYW5hZ2Vycy9zY2VuYXJpby1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3NwZWNpYWwtb3BlcmF0aW9ucy5qcyIsInNyYy9tYW5hZ2Vycy93b3JsZC1tYW5hZ2VyLmpzIiwic3JjL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyLmpzIiwic3JjL3N0b3JlL2Nvb2tpZS1zdG9yZS5qcyIsInNyYy9zdG9yZS9zdG9yZS1mYWN0b3J5LmpzIiwic3JjL3RyYW5zcG9ydC9hamF4LWh0dHAtdHJhbnNwb3J0LmpzIiwic3JjL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5LmpzIiwic3JjL3V0aWwvaW5oZXJpdC5qcyIsInNyYy91dGlsL21ha2Utc2VxdWVuY2UuanMiLCJzcmMvdXRpbC9vYmplY3QtdXRpbC5qcyIsInNyYy91dGlsL3F1ZXJ5LXV0aWwuanMiLCJzcmMvdXRpbC9ydW4tdXRpbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN4Z0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwV0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMVRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0UUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25LQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzdUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLyohXG4gKiBUaGUgYnVmZmVyIG1vZHVsZSBmcm9tIG5vZGUuanMsIGZvciB0aGUgYnJvd3Nlci5cbiAqXG4gKiBAYXV0aG9yICAgRmVyb3NzIEFib3VraGFkaWplaCA8ZmVyb3NzQGZlcm9zcy5vcmc+IDxodHRwOi8vZmVyb3NzLm9yZz5cbiAqIEBsaWNlbnNlICBNSVRcbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tcHJvdG8gKi9cblxudmFyIGJhc2U2NCA9IHJlcXVpcmUoJ2Jhc2U2NC1qcycpXG52YXIgaWVlZTc1NCA9IHJlcXVpcmUoJ2llZWU3NTQnKVxudmFyIGlzQXJyYXkgPSByZXF1aXJlKCdpcy1hcnJheScpXG5cbmV4cG9ydHMuQnVmZmVyID0gQnVmZmVyXG5leHBvcnRzLlNsb3dCdWZmZXIgPSBTbG93QnVmZmVyXG5leHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTID0gNTBcbkJ1ZmZlci5wb29sU2l6ZSA9IDgxOTIgLy8gbm90IHVzZWQgYnkgdGhpcyBpbXBsZW1lbnRhdGlvblxuXG52YXIgcm9vdFBhcmVudCA9IHt9XG5cbi8qKlxuICogSWYgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYDpcbiAqICAgPT09IHRydWUgICAgVXNlIFVpbnQ4QXJyYXkgaW1wbGVtZW50YXRpb24gKGZhc3Rlc3QpXG4gKiAgID09PSBmYWxzZSAgIFVzZSBPYmplY3QgaW1wbGVtZW50YXRpb24gKG1vc3QgY29tcGF0aWJsZSwgZXZlbiBJRTYpXG4gKlxuICogQnJvd3NlcnMgdGhhdCBzdXBwb3J0IHR5cGVkIGFycmF5cyBhcmUgSUUgMTArLCBGaXJlZm94IDQrLCBDaHJvbWUgNyssIFNhZmFyaSA1LjErLFxuICogT3BlcmEgMTEuNissIGlPUyA0LjIrLlxuICpcbiAqIER1ZSB0byB2YXJpb3VzIGJyb3dzZXIgYnVncywgc29tZXRpbWVzIHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24gd2lsbCBiZSB1c2VkIGV2ZW5cbiAqIHdoZW4gdGhlIGJyb3dzZXIgc3VwcG9ydHMgdHlwZWQgYXJyYXlzLlxuICpcbiAqIE5vdGU6XG4gKlxuICogICAtIEZpcmVmb3ggNC0yOSBsYWNrcyBzdXBwb3J0IGZvciBhZGRpbmcgbmV3IHByb3BlcnRpZXMgdG8gYFVpbnQ4QXJyYXlgIGluc3RhbmNlcyxcbiAqICAgICBTZWU6IGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTY5NTQzOC5cbiAqXG4gKiAgIC0gU2FmYXJpIDUtNyBsYWNrcyBzdXBwb3J0IGZvciBjaGFuZ2luZyB0aGUgYE9iamVjdC5wcm90b3R5cGUuY29uc3RydWN0b3JgIHByb3BlcnR5XG4gKiAgICAgb24gb2JqZWN0cy5cbiAqXG4gKiAgIC0gQ2hyb21lIDktMTAgaXMgbWlzc2luZyB0aGUgYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbi5cbiAqXG4gKiAgIC0gSUUxMCBoYXMgYSBicm9rZW4gYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGFycmF5cyBvZlxuICogICAgIGluY29ycmVjdCBsZW5ndGggaW4gc29tZSBzaXR1YXRpb25zLlxuXG4gKiBXZSBkZXRlY3QgdGhlc2UgYnVnZ3kgYnJvd3NlcnMgYW5kIHNldCBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgIHRvIGBmYWxzZWAgc28gdGhleVxuICogZ2V0IHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24sIHdoaWNoIGlzIHNsb3dlciBidXQgYmVoYXZlcyBjb3JyZWN0bHkuXG4gKi9cbkJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUID0gZ2xvYmFsLlRZUEVEX0FSUkFZX1NVUFBPUlQgIT09IHVuZGVmaW5lZFxuICA/IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gIDogdHlwZWRBcnJheVN1cHBvcnQoKVxuXG5mdW5jdGlvbiB0eXBlZEFycmF5U3VwcG9ydCAoKSB7XG4gIGZ1bmN0aW9uIEJhciAoKSB7fVxuICB0cnkge1xuICAgIHZhciBhcnIgPSBuZXcgVWludDhBcnJheSgxKVxuICAgIGFyci5mb28gPSBmdW5jdGlvbiAoKSB7IHJldHVybiA0MiB9XG4gICAgYXJyLmNvbnN0cnVjdG9yID0gQmFyXG4gICAgcmV0dXJuIGFyci5mb28oKSA9PT0gNDIgJiYgLy8gdHlwZWQgYXJyYXkgaW5zdGFuY2VzIGNhbiBiZSBhdWdtZW50ZWRcbiAgICAgICAgYXJyLmNvbnN0cnVjdG9yID09PSBCYXIgJiYgLy8gY29uc3RydWN0b3IgY2FuIGJlIHNldFxuICAgICAgICB0eXBlb2YgYXJyLnN1YmFycmF5ID09PSAnZnVuY3Rpb24nICYmIC8vIGNocm9tZSA5LTEwIGxhY2sgYHN1YmFycmF5YFxuICAgICAgICBhcnIuc3ViYXJyYXkoMSwgMSkuYnl0ZUxlbmd0aCA9PT0gMCAvLyBpZTEwIGhhcyBicm9rZW4gYHN1YmFycmF5YFxuICB9IGNhdGNoIChlKSB7XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuZnVuY3Rpb24ga01heExlbmd0aCAoKSB7XG4gIHJldHVybiBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVFxuICAgID8gMHg3ZmZmZmZmZlxuICAgIDogMHgzZmZmZmZmZlxufVxuXG4vKipcbiAqIENsYXNzOiBCdWZmZXJcbiAqID09PT09PT09PT09PT1cbiAqXG4gKiBUaGUgQnVmZmVyIGNvbnN0cnVjdG9yIHJldHVybnMgaW5zdGFuY2VzIG9mIGBVaW50OEFycmF5YCB0aGF0IGFyZSBhdWdtZW50ZWRcbiAqIHdpdGggZnVuY3Rpb24gcHJvcGVydGllcyBmb3IgYWxsIHRoZSBub2RlIGBCdWZmZXJgIEFQSSBmdW5jdGlvbnMuIFdlIHVzZVxuICogYFVpbnQ4QXJyYXlgIHNvIHRoYXQgc3F1YXJlIGJyYWNrZXQgbm90YXRpb24gd29ya3MgYXMgZXhwZWN0ZWQgLS0gaXQgcmV0dXJuc1xuICogYSBzaW5nbGUgb2N0ZXQuXG4gKlxuICogQnkgYXVnbWVudGluZyB0aGUgaW5zdGFuY2VzLCB3ZSBjYW4gYXZvaWQgbW9kaWZ5aW5nIHRoZSBgVWludDhBcnJheWBcbiAqIHByb3RvdHlwZS5cbiAqL1xuZnVuY3Rpb24gQnVmZmVyIChhcmcpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIEJ1ZmZlcikpIHtcbiAgICAvLyBBdm9pZCBnb2luZyB0aHJvdWdoIGFuIEFyZ3VtZW50c0FkYXB0b3JUcmFtcG9saW5lIGluIHRoZSBjb21tb24gY2FzZS5cbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIHJldHVybiBuZXcgQnVmZmVyKGFyZywgYXJndW1lbnRzWzFdKVxuICAgIHJldHVybiBuZXcgQnVmZmVyKGFyZylcbiAgfVxuXG4gIHRoaXMubGVuZ3RoID0gMFxuICB0aGlzLnBhcmVudCA9IHVuZGVmaW5lZFxuXG4gIC8vIENvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ251bWJlcicpIHtcbiAgICByZXR1cm4gZnJvbU51bWJlcih0aGlzLCBhcmcpXG4gIH1cblxuICAvLyBTbGlnaHRseSBsZXNzIGNvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gZnJvbVN0cmluZyh0aGlzLCBhcmcsIGFyZ3VtZW50cy5sZW5ndGggPiAxID8gYXJndW1lbnRzWzFdIDogJ3V0ZjgnKVxuICB9XG5cbiAgLy8gVW51c3VhbC5cbiAgcmV0dXJuIGZyb21PYmplY3QodGhpcywgYXJnKVxufVxuXG5mdW5jdGlvbiBmcm9tTnVtYmVyICh0aGF0LCBsZW5ndGgpIHtcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aCA8IDAgPyAwIDogY2hlY2tlZChsZW5ndGgpIHwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHRoYXRbaV0gPSAwXG4gICAgfVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21TdHJpbmcgKHRoYXQsIHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBlbmNvZGluZyAhPT0gJ3N0cmluZycgfHwgZW5jb2RpbmcgPT09ICcnKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIC8vIEFzc3VtcHRpb246IGJ5dGVMZW5ndGgoKSByZXR1cm4gdmFsdWUgaXMgYWx3YXlzIDwga01heExlbmd0aC5cbiAgdmFyIGxlbmd0aCA9IGJ5dGVMZW5ndGgoc3RyaW5nLCBlbmNvZGluZykgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG5cbiAgdGhhdC53cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihvYmplY3QpKSByZXR1cm4gZnJvbUJ1ZmZlcih0aGF0LCBvYmplY3QpXG5cbiAgaWYgKGlzQXJyYXkob2JqZWN0KSkgcmV0dXJuIGZyb21BcnJheSh0aGF0LCBvYmplY3QpXG5cbiAgaWYgKG9iamVjdCA9PSBudWxsKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignbXVzdCBzdGFydCB3aXRoIG51bWJlciwgYnVmZmVyLCBhcnJheSBvciBzdHJpbmcnKVxuICB9XG5cbiAgaWYgKHR5cGVvZiBBcnJheUJ1ZmZlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAob2JqZWN0LmJ1ZmZlciBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgICByZXR1cm4gZnJvbVR5cGVkQXJyYXkodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgICBpZiAob2JqZWN0IGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICAgIHJldHVybiBmcm9tQXJyYXlCdWZmZXIodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgfVxuXG4gIGlmIChvYmplY3QubGVuZ3RoKSByZXR1cm4gZnJvbUFycmF5TGlrZSh0aGF0LCBvYmplY3QpXG5cbiAgcmV0dXJuIGZyb21Kc29uT2JqZWN0KHRoYXQsIG9iamVjdClcbn1cblxuZnVuY3Rpb24gZnJvbUJ1ZmZlciAodGhhdCwgYnVmZmVyKSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGJ1ZmZlci5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICBidWZmZXIuY29weSh0aGF0LCAwLCAwLCBsZW5ndGgpXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheSAodGhhdCwgYXJyYXkpIHtcbiAgdmFyIGxlbmd0aCA9IGNoZWNrZWQoYXJyYXkubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbi8vIER1cGxpY2F0ZSBvZiBmcm9tQXJyYXkoKSB0byBrZWVwIGZyb21BcnJheSgpIG1vbm9tb3JwaGljLlxuZnVuY3Rpb24gZnJvbVR5cGVkQXJyYXkgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIC8vIFRydW5jYXRpbmcgdGhlIGVsZW1lbnRzIGlzIHByb2JhYmx5IG5vdCB3aGF0IHBlb3BsZSBleHBlY3QgZnJvbSB0eXBlZFxuICAvLyBhcnJheXMgd2l0aCBCWVRFU19QRVJfRUxFTUVOVCA+IDEgYnV0IGl0J3MgY29tcGF0aWJsZSB3aXRoIHRoZSBiZWhhdmlvclxuICAvLyBvZiB0aGUgb2xkIEJ1ZmZlciBjb25zdHJ1Y3Rvci5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUJ1ZmZlciAodGhhdCwgYXJyYXkpIHtcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgYXJyYXkuYnl0ZUxlbmd0aFxuICAgIHRoYXQgPSBCdWZmZXIuX2F1Z21lbnQobmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0ID0gZnJvbVR5cGVkQXJyYXkodGhhdCwgbmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUxpa2UgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vLyBEZXNlcmlhbGl6ZSB7IHR5cGU6ICdCdWZmZXInLCBkYXRhOiBbMSwyLDMsLi4uXSB9IGludG8gYSBCdWZmZXIgb2JqZWN0LlxuLy8gUmV0dXJucyBhIHplcm8tbGVuZ3RoIGJ1ZmZlciBmb3IgaW5wdXRzIHRoYXQgZG9uJ3QgY29uZm9ybSB0byB0aGUgc3BlYy5cbmZ1bmN0aW9uIGZyb21Kc29uT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgdmFyIGFycmF5XG4gIHZhciBsZW5ndGggPSAwXG5cbiAgaWYgKG9iamVjdC50eXBlID09PSAnQnVmZmVyJyAmJiBpc0FycmF5KG9iamVjdC5kYXRhKSkge1xuICAgIGFycmF5ID0gb2JqZWN0LmRhdGFcbiAgICBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIH1cbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gIEJ1ZmZlci5wcm90b3R5cGUuX19wcm90b19fID0gVWludDhBcnJheS5wcm90b3R5cGVcbiAgQnVmZmVyLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXlcbn1cblxuZnVuY3Rpb24gYWxsb2NhdGUgKHRoYXQsIGxlbmd0aCkge1xuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAvLyBSZXR1cm4gYW4gYXVnbWVudGVkIGBVaW50OEFycmF5YCBpbnN0YW5jZSwgZm9yIGJlc3QgcGVyZm9ybWFuY2VcbiAgICB0aGF0ID0gQnVmZmVyLl9hdWdtZW50KG5ldyBVaW50OEFycmF5KGxlbmd0aCkpXG4gICAgdGhhdC5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgLy8gRmFsbGJhY2s6IFJldHVybiBhbiBvYmplY3QgaW5zdGFuY2Ugb2YgdGhlIEJ1ZmZlciBjbGFzc1xuICAgIHRoYXQubGVuZ3RoID0gbGVuZ3RoXG4gICAgdGhhdC5faXNCdWZmZXIgPSB0cnVlXG4gIH1cblxuICB2YXIgZnJvbVBvb2wgPSBsZW5ndGggIT09IDAgJiYgbGVuZ3RoIDw9IEJ1ZmZlci5wb29sU2l6ZSA+Pj4gMVxuICBpZiAoZnJvbVBvb2wpIHRoYXQucGFyZW50ID0gcm9vdFBhcmVudFxuXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGNoZWNrZWQgKGxlbmd0aCkge1xuICAvLyBOb3RlOiBjYW5ub3QgdXNlIGBsZW5ndGggPCBrTWF4TGVuZ3RoYCBoZXJlIGJlY2F1c2UgdGhhdCBmYWlscyB3aGVuXG4gIC8vIGxlbmd0aCBpcyBOYU4gKHdoaWNoIGlzIG90aGVyd2lzZSBjb2VyY2VkIHRvIHplcm8uKVxuICBpZiAobGVuZ3RoID49IGtNYXhMZW5ndGgoKSkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIGFsbG9jYXRlIEJ1ZmZlciBsYXJnZXIgdGhhbiBtYXhpbXVtICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICdzaXplOiAweCcgKyBrTWF4TGVuZ3RoKCkudG9TdHJpbmcoMTYpICsgJyBieXRlcycpXG4gIH1cbiAgcmV0dXJuIGxlbmd0aCB8IDBcbn1cblxuZnVuY3Rpb24gU2xvd0J1ZmZlciAoc3ViamVjdCwgZW5jb2RpbmcpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFNsb3dCdWZmZXIpKSByZXR1cm4gbmV3IFNsb3dCdWZmZXIoc3ViamVjdCwgZW5jb2RpbmcpXG5cbiAgdmFyIGJ1ZiA9IG5ldyBCdWZmZXIoc3ViamVjdCwgZW5jb2RpbmcpXG4gIGRlbGV0ZSBidWYucGFyZW50XG4gIHJldHVybiBidWZcbn1cblxuQnVmZmVyLmlzQnVmZmVyID0gZnVuY3Rpb24gaXNCdWZmZXIgKGIpIHtcbiAgcmV0dXJuICEhKGIgIT0gbnVsbCAmJiBiLl9pc0J1ZmZlcilcbn1cblxuQnVmZmVyLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChhLCBiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGEpIHx8ICFCdWZmZXIuaXNCdWZmZXIoYikpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudHMgbXVzdCBiZSBCdWZmZXJzJylcbiAgfVxuXG4gIGlmIChhID09PSBiKSByZXR1cm4gMFxuXG4gIHZhciB4ID0gYS5sZW5ndGhcbiAgdmFyIHkgPSBiLmxlbmd0aFxuXG4gIHZhciBpID0gMFxuICB2YXIgbGVuID0gTWF0aC5taW4oeCwgeSlcbiAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICBpZiAoYVtpXSAhPT0gYltpXSkgYnJlYWtcblxuICAgICsraVxuICB9XG5cbiAgaWYgKGkgIT09IGxlbikge1xuICAgIHggPSBhW2ldXG4gICAgeSA9IGJbaV1cbiAgfVxuXG4gIGlmICh4IDwgeSkgcmV0dXJuIC0xXG4gIGlmICh5IDwgeCkgcmV0dXJuIDFcbiAgcmV0dXJuIDBcbn1cblxuQnVmZmVyLmlzRW5jb2RpbmcgPSBmdW5jdGlvbiBpc0VuY29kaW5nIChlbmNvZGluZykge1xuICBzd2l0Y2ggKFN0cmluZyhlbmNvZGluZykudG9Mb3dlckNhc2UoKSkge1xuICAgIGNhc2UgJ2hleCc6XG4gICAgY2FzZSAndXRmOCc6XG4gICAgY2FzZSAndXRmLTgnOlxuICAgIGNhc2UgJ2FzY2lpJzpcbiAgICBjYXNlICdiaW5hcnknOlxuICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgY2FzZSAncmF3JzpcbiAgICBjYXNlICd1Y3MyJzpcbiAgICBjYXNlICd1Y3MtMic6XG4gICAgY2FzZSAndXRmMTZsZSc6XG4gICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgcmV0dXJuIHRydWVcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuQnVmZmVyLmNvbmNhdCA9IGZ1bmN0aW9uIGNvbmNhdCAobGlzdCwgbGVuZ3RoKSB7XG4gIGlmICghaXNBcnJheShsaXN0KSkgdGhyb3cgbmV3IFR5cGVFcnJvcignbGlzdCBhcmd1bWVudCBtdXN0IGJlIGFuIEFycmF5IG9mIEJ1ZmZlcnMuJylcblxuICBpZiAobGlzdC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcigwKVxuICB9XG5cbiAgdmFyIGlcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbGVuZ3RoID0gMFxuICAgIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBsZW5ndGggKz0gbGlzdFtpXS5sZW5ndGhcbiAgICB9XG4gIH1cblxuICB2YXIgYnVmID0gbmV3IEJ1ZmZlcihsZW5ndGgpXG4gIHZhciBwb3MgPSAwXG4gIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGl0ZW0gPSBsaXN0W2ldXG4gICAgaXRlbS5jb3B5KGJ1ZiwgcG9zKVxuICAgIHBvcyArPSBpdGVtLmxlbmd0aFxuICB9XG4gIHJldHVybiBidWZcbn1cblxuZnVuY3Rpb24gYnl0ZUxlbmd0aCAoc3RyaW5nLCBlbmNvZGluZykge1xuICBpZiAodHlwZW9mIHN0cmluZyAhPT0gJ3N0cmluZycpIHN0cmluZyA9ICcnICsgc3RyaW5nXG5cbiAgdmFyIGxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKGxlbiA9PT0gMCkgcmV0dXJuIDBcblxuICAvLyBVc2UgYSBmb3IgbG9vcCB0byBhdm9pZCByZWN1cnNpb25cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAvLyBEZXByZWNhdGVkXG4gICAgICBjYXNlICdyYXcnOlxuICAgICAgY2FzZSAncmF3cyc6XG4gICAgICAgIHJldHVybiBsZW5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGhcbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiBsZW4gKiAyXG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gbGVuID4+PiAxXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICByZXR1cm4gYmFzZTY0VG9CeXRlcyhzdHJpbmcpLmxlbmd0aFxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSByZXR1cm4gdXRmOFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGggLy8gYXNzdW1lIHV0ZjhcbiAgICAgICAgZW5jb2RpbmcgPSAoJycgKyBlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cbkJ1ZmZlci5ieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aFxuXG4vLyBwcmUtc2V0IGZvciB2YWx1ZXMgdGhhdCBtYXkgZXhpc3QgaW4gdGhlIGZ1dHVyZVxuQnVmZmVyLnByb3RvdHlwZS5sZW5ndGggPSB1bmRlZmluZWRcbkJ1ZmZlci5wcm90b3R5cGUucGFyZW50ID0gdW5kZWZpbmVkXG5cbmZ1bmN0aW9uIHNsb3dUb1N0cmluZyAoZW5jb2RpbmcsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcblxuICBzdGFydCA9IHN0YXJ0IHwgMFxuICBlbmQgPSBlbmQgPT09IHVuZGVmaW5lZCB8fCBlbmQgPT09IEluZmluaXR5ID8gdGhpcy5sZW5ndGggOiBlbmQgfCAwXG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcbiAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKGVuZCA8PSBzdGFydCkgcmV0dXJuICcnXG5cbiAgd2hpbGUgKHRydWUpIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1dGYxNmxlU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKGVuY29kaW5nICsgJycpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9TdHJpbmcgPSBmdW5jdGlvbiB0b1N0cmluZyAoKSB7XG4gIHZhciBsZW5ndGggPSB0aGlzLmxlbmd0aCB8IDBcbiAgaWYgKGxlbmd0aCA9PT0gMCkgcmV0dXJuICcnXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSByZXR1cm4gdXRmOFNsaWNlKHRoaXMsIDAsIGxlbmd0aClcbiAgcmV0dXJuIHNsb3dUb1N0cmluZy5hcHBseSh0aGlzLCBhcmd1bWVudHMpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24gZXF1YWxzIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiB0cnVlXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKSA9PT0gMFxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluc3BlY3QgPSBmdW5jdGlvbiBpbnNwZWN0ICgpIHtcbiAgdmFyIHN0ciA9ICcnXG4gIHZhciBtYXggPSBleHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTXG4gIGlmICh0aGlzLmxlbmd0aCA+IDApIHtcbiAgICBzdHIgPSB0aGlzLnRvU3RyaW5nKCdoZXgnLCAwLCBtYXgpLm1hdGNoKC8uezJ9L2cpLmpvaW4oJyAnKVxuICAgIGlmICh0aGlzLmxlbmd0aCA+IG1heCkgc3RyICs9ICcgLi4uICdcbiAgfVxuICByZXR1cm4gJzxCdWZmZXIgJyArIHN0ciArICc+J1xufVxuXG5CdWZmZXIucHJvdG90eXBlLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiAwXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluZGV4T2YgPSBmdW5jdGlvbiBpbmRleE9mICh2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgaWYgKGJ5dGVPZmZzZXQgPiAweDdmZmZmZmZmKSBieXRlT2Zmc2V0ID0gMHg3ZmZmZmZmZlxuICBlbHNlIGlmIChieXRlT2Zmc2V0IDwgLTB4ODAwMDAwMDApIGJ5dGVPZmZzZXQgPSAtMHg4MDAwMDAwMFxuICBieXRlT2Zmc2V0ID4+PSAwXG5cbiAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gLTFcbiAgaWYgKGJ5dGVPZmZzZXQgPj0gdGhpcy5sZW5ndGgpIHJldHVybiAtMVxuXG4gIC8vIE5lZ2F0aXZlIG9mZnNldHMgc3RhcnQgZnJvbSB0aGUgZW5kIG9mIHRoZSBidWZmZXJcbiAgaWYgKGJ5dGVPZmZzZXQgPCAwKSBieXRlT2Zmc2V0ID0gTWF0aC5tYXgodGhpcy5sZW5ndGggKyBieXRlT2Zmc2V0LCAwKVxuXG4gIGlmICh0eXBlb2YgdmFsID09PSAnc3RyaW5nJykge1xuICAgIGlmICh2YWwubGVuZ3RoID09PSAwKSByZXR1cm4gLTEgLy8gc3BlY2lhbCBjYXNlOiBsb29raW5nIGZvciBlbXB0eSBzdHJpbmcgYWx3YXlzIGZhaWxzXG4gICAgcmV0dXJuIFN0cmluZy5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAoQnVmZmVyLmlzQnVmZmVyKHZhbCkpIHtcbiAgICByZXR1cm4gYXJyYXlJbmRleE9mKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ251bWJlcicpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQgJiYgVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgcmV0dXJuIFVpbnQ4QXJyYXkucHJvdG90eXBlLmluZGV4T2YuY2FsbCh0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gICAgfVxuICAgIHJldHVybiBhcnJheUluZGV4T2YodGhpcywgWyB2YWwgXSwgYnl0ZU9mZnNldClcbiAgfVxuXG4gIGZ1bmN0aW9uIGFycmF5SW5kZXhPZiAoYXJyLCB2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgICB2YXIgZm91bmRJbmRleCA9IC0xXG4gICAgZm9yICh2YXIgaSA9IDA7IGJ5dGVPZmZzZXQgKyBpIDwgYXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoYXJyW2J5dGVPZmZzZXQgKyBpXSA9PT0gdmFsW2ZvdW5kSW5kZXggPT09IC0xID8gMCA6IGkgLSBmb3VuZEluZGV4XSkge1xuICAgICAgICBpZiAoZm91bmRJbmRleCA9PT0gLTEpIGZvdW5kSW5kZXggPSBpXG4gICAgICAgIGlmIChpIC0gZm91bmRJbmRleCArIDEgPT09IHZhbC5sZW5ndGgpIHJldHVybiBieXRlT2Zmc2V0ICsgZm91bmRJbmRleFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZm91bmRJbmRleCA9IC0xXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAtMVxuICB9XG5cbiAgdGhyb3cgbmV3IFR5cGVFcnJvcigndmFsIG11c3QgYmUgc3RyaW5nLCBudW1iZXIgb3IgQnVmZmVyJylcbn1cblxuLy8gYGdldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5nZXQgPSBmdW5jdGlvbiBnZXQgKG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLmdldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMucmVhZFVJbnQ4KG9mZnNldClcbn1cblxuLy8gYHNldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5zZXQgPSBmdW5jdGlvbiBzZXQgKHYsIG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLnNldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMud3JpdGVVSW50OCh2LCBvZmZzZXQpXG59XG5cbmZ1bmN0aW9uIGhleFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgb2Zmc2V0ID0gTnVtYmVyKG9mZnNldCkgfHwgMFxuICB2YXIgcmVtYWluaW5nID0gYnVmLmxlbmd0aCAtIG9mZnNldFxuICBpZiAoIWxlbmd0aCkge1xuICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICB9IGVsc2Uge1xuICAgIGxlbmd0aCA9IE51bWJlcihsZW5ndGgpXG4gICAgaWYgKGxlbmd0aCA+IHJlbWFpbmluZykge1xuICAgICAgbGVuZ3RoID0gcmVtYWluaW5nXG4gICAgfVxuICB9XG5cbiAgLy8gbXVzdCBiZSBhbiBldmVuIG51bWJlciBvZiBkaWdpdHNcbiAgdmFyIHN0ckxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKHN0ckxlbiAlIDIgIT09IDApIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcblxuICBpZiAobGVuZ3RoID4gc3RyTGVuIC8gMikge1xuICAgIGxlbmd0aCA9IHN0ckxlbiAvIDJcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHBhcnNlZCA9IHBhcnNlSW50KHN0cmluZy5zdWJzdHIoaSAqIDIsIDIpLCAxNilcbiAgICBpZiAoaXNOYU4ocGFyc2VkKSkgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGhleCBzdHJpbmcnKVxuICAgIGJ1ZltvZmZzZXQgKyBpXSA9IHBhcnNlZFxuICB9XG4gIHJldHVybiBpXG59XG5cbmZ1bmN0aW9uIHV0ZjhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKHV0ZjhUb0J5dGVzKHN0cmluZywgYnVmLmxlbmd0aCAtIG9mZnNldCksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGFzY2lpV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcihhc2NpaVRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYmluYXJ5V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYXNjaWlXcml0ZShidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGJhc2U2NFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIoYmFzZTY0VG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiB1Y3MyV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcih1dGYxNmxlVG9CeXRlcyhzdHJpbmcsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlID0gZnVuY3Rpb24gd3JpdGUgKHN0cmluZywgb2Zmc2V0LCBsZW5ndGgsIGVuY29kaW5nKSB7XG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcpXG4gIGlmIChvZmZzZXQgPT09IHVuZGVmaW5lZCkge1xuICAgIGVuY29kaW5nID0gJ3V0ZjgnXG4gICAgbGVuZ3RoID0gdGhpcy5sZW5ndGhcbiAgICBvZmZzZXQgPSAwXG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICB9IGVsc2UgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkICYmIHR5cGVvZiBvZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgZW5jb2RpbmcgPSBvZmZzZXRcbiAgICBsZW5ndGggPSB0aGlzLmxlbmd0aFxuICAgIG9mZnNldCA9IDBcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZywgb2Zmc2V0WywgbGVuZ3RoXVssIGVuY29kaW5nXSlcbiAgfSBlbHNlIGlmIChpc0Zpbml0ZShvZmZzZXQpKSB7XG4gICAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICAgIGlmIChpc0Zpbml0ZShsZW5ndGgpKSB7XG4gICAgICBsZW5ndGggPSBsZW5ndGggfCAwXG4gICAgICBpZiAoZW5jb2RpbmcgPT09IHVuZGVmaW5lZCkgZW5jb2RpbmcgPSAndXRmOCdcbiAgICB9IGVsc2Uge1xuICAgICAgZW5jb2RpbmcgPSBsZW5ndGhcbiAgICAgIGxlbmd0aCA9IHVuZGVmaW5lZFxuICAgIH1cbiAgLy8gbGVnYWN5IHdyaXRlKHN0cmluZywgZW5jb2RpbmcsIG9mZnNldCwgbGVuZ3RoKSAtIHJlbW92ZSBpbiB2MC4xM1xuICB9IGVsc2Uge1xuICAgIHZhciBzd2FwID0gZW5jb2RpbmdcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIG9mZnNldCA9IGxlbmd0aCB8IDBcbiAgICBsZW5ndGggPSBzd2FwXG4gIH1cblxuICB2YXIgcmVtYWluaW5nID0gdGhpcy5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkIHx8IGxlbmd0aCA+IHJlbWFpbmluZykgbGVuZ3RoID0gcmVtYWluaW5nXG5cbiAgaWYgKChzdHJpbmcubGVuZ3RoID4gMCAmJiAobGVuZ3RoIDwgMCB8fCBvZmZzZXQgPCAwKSkgfHwgb2Zmc2V0ID4gdGhpcy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignYXR0ZW1wdCB0byB3cml0ZSBvdXRzaWRlIGJ1ZmZlciBib3VuZHMnKVxuICB9XG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcblxuICB2YXIgbG93ZXJlZENhc2UgPSBmYWxzZVxuICBmb3IgKDs7KSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGhleFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgICAgcmV0dXJuIGFzY2lpV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgICAgcmV0dXJuIGJpbmFyeVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIC8vIFdhcm5pbmc6IG1heExlbmd0aCBub3QgdGFrZW4gaW50byBhY2NvdW50IGluIGJhc2U2NFdyaXRlXG4gICAgICAgIHJldHVybiBiYXNlNjRXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gdWNzMldyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgICAgICBlbmNvZGluZyA9ICgnJyArIGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvSlNPTiA9IGZ1bmN0aW9uIHRvSlNPTiAoKSB7XG4gIHJldHVybiB7XG4gICAgdHlwZTogJ0J1ZmZlcicsXG4gICAgZGF0YTogQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodGhpcy5fYXJyIHx8IHRoaXMsIDApXG4gIH1cbn1cblxuZnVuY3Rpb24gYmFzZTY0U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICBpZiAoc3RhcnQgPT09IDAgJiYgZW5kID09PSBidWYubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGJhc2U2NC5mcm9tQnl0ZUFycmF5KGJ1ZilcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmLnNsaWNlKHN0YXJ0LCBlbmQpKVxuICB9XG59XG5cbmZ1bmN0aW9uIHV0ZjhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcbiAgdmFyIHJlcyA9IFtdXG5cbiAgdmFyIGkgPSBzdGFydFxuICB3aGlsZSAoaSA8IGVuZCkge1xuICAgIHZhciBmaXJzdEJ5dGUgPSBidWZbaV1cbiAgICB2YXIgY29kZVBvaW50ID0gbnVsbFxuICAgIHZhciBieXRlc1BlclNlcXVlbmNlID0gKGZpcnN0Qnl0ZSA+IDB4RUYpID8gNFxuICAgICAgOiAoZmlyc3RCeXRlID4gMHhERikgPyAzXG4gICAgICA6IChmaXJzdEJ5dGUgPiAweEJGKSA/IDJcbiAgICAgIDogMVxuXG4gICAgaWYgKGkgKyBieXRlc1BlclNlcXVlbmNlIDw9IGVuZCkge1xuICAgICAgdmFyIHNlY29uZEJ5dGUsIHRoaXJkQnl0ZSwgZm91cnRoQnl0ZSwgdGVtcENvZGVQb2ludFxuXG4gICAgICBzd2l0Y2ggKGJ5dGVzUGVyU2VxdWVuY2UpIHtcbiAgICAgICAgY2FzZSAxOlxuICAgICAgICAgIGlmIChmaXJzdEJ5dGUgPCAweDgwKSB7XG4gICAgICAgICAgICBjb2RlUG9pbnQgPSBmaXJzdEJ5dGVcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHgxRikgPDwgMHg2IHwgKHNlY29uZEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweDdGKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwICYmICh0aGlyZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4QyB8IChzZWNvbmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKHRoaXJkQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0ZGICYmICh0ZW1wQ29kZVBvaW50IDwgMHhEODAwIHx8IHRlbXBDb2RlUG9pbnQgPiAweERGRkYpKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSA0OlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGZvdXJ0aEJ5dGUgPSBidWZbaSArIDNdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwICYmIChmb3VydGhCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHhGKSA8PCAweDEyIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweEMgfCAodGhpcmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKGZvdXJ0aEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweEZGRkYgJiYgdGVtcENvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGNvZGVQb2ludCA9PT0gbnVsbCkge1xuICAgICAgLy8gd2UgZGlkIG5vdCBnZW5lcmF0ZSBhIHZhbGlkIGNvZGVQb2ludCBzbyBpbnNlcnQgYVxuICAgICAgLy8gcmVwbGFjZW1lbnQgY2hhciAoVStGRkZEKSBhbmQgYWR2YW5jZSBvbmx5IDEgYnl0ZVxuICAgICAgY29kZVBvaW50ID0gMHhGRkZEXG4gICAgICBieXRlc1BlclNlcXVlbmNlID0gMVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50ID4gMHhGRkZGKSB7XG4gICAgICAvLyBlbmNvZGUgdG8gdXRmMTYgKHN1cnJvZ2F0ZSBwYWlyIGRhbmNlKVxuICAgICAgY29kZVBvaW50IC09IDB4MTAwMDBcbiAgICAgIHJlcy5wdXNoKGNvZGVQb2ludCA+Pj4gMTAgJiAweDNGRiB8IDB4RDgwMClcbiAgICAgIGNvZGVQb2ludCA9IDB4REMwMCB8IGNvZGVQb2ludCAmIDB4M0ZGXG4gICAgfVxuXG4gICAgcmVzLnB1c2goY29kZVBvaW50KVxuICAgIGkgKz0gYnl0ZXNQZXJTZXF1ZW5jZVxuICB9XG5cbiAgcmV0dXJuIGRlY29kZUNvZGVQb2ludHNBcnJheShyZXMpXG59XG5cbi8vIEJhc2VkIG9uIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzIyNzQ3MjcyLzY4MDc0MiwgdGhlIGJyb3dzZXIgd2l0aFxuLy8gdGhlIGxvd2VzdCBsaW1pdCBpcyBDaHJvbWUsIHdpdGggMHgxMDAwMCBhcmdzLlxuLy8gV2UgZ28gMSBtYWduaXR1ZGUgbGVzcywgZm9yIHNhZmV0eVxudmFyIE1BWF9BUkdVTUVOVFNfTEVOR1RIID0gMHgxMDAwXG5cbmZ1bmN0aW9uIGRlY29kZUNvZGVQb2ludHNBcnJheSAoY29kZVBvaW50cykge1xuICB2YXIgbGVuID0gY29kZVBvaW50cy5sZW5ndGhcbiAgaWYgKGxlbiA8PSBNQVhfQVJHVU1FTlRTX0xFTkdUSCkge1xuICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFN0cmluZywgY29kZVBvaW50cykgLy8gYXZvaWQgZXh0cmEgc2xpY2UoKVxuICB9XG5cbiAgLy8gRGVjb2RlIGluIGNodW5rcyB0byBhdm9pZCBcImNhbGwgc3RhY2sgc2l6ZSBleGNlZWRlZFwiLlxuICB2YXIgcmVzID0gJydcbiAgdmFyIGkgPSAwXG4gIHdoaWxlIChpIDwgbGVuKSB7XG4gICAgcmVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoXG4gICAgICBTdHJpbmcsXG4gICAgICBjb2RlUG9pbnRzLnNsaWNlKGksIGkgKz0gTUFYX0FSR1VNRU5UU19MRU5HVEgpXG4gICAgKVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0gJiAweDdGKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gYmluYXJ5U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgcmV0ID0gJydcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgcmV0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnVmW2ldKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gaGV4U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gYnVmLmxlbmd0aFxuXG4gIGlmICghc3RhcnQgfHwgc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgfHwgZW5kIDwgMCB8fCBlbmQgPiBsZW4pIGVuZCA9IGxlblxuXG4gIHZhciBvdXQgPSAnJ1xuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIG91dCArPSB0b0hleChidWZbaV0pXG4gIH1cbiAgcmV0dXJuIG91dFxufVxuXG5mdW5jdGlvbiB1dGYxNmxlU2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgYnl0ZXMgPSBidWYuc2xpY2Uoc3RhcnQsIGVuZClcbiAgdmFyIHJlcyA9ICcnXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShieXRlc1tpXSArIGJ5dGVzW2kgKyAxXSAqIDI1NilcbiAgfVxuICByZXR1cm4gcmVzXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuc2xpY2UgPSBmdW5jdGlvbiBzbGljZSAoc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gdGhpcy5sZW5ndGhcbiAgc3RhcnQgPSB+fnN0YXJ0XG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkID8gbGVuIDogfn5lbmRcblxuICBpZiAoc3RhcnQgPCAwKSB7XG4gICAgc3RhcnQgKz0gbGVuXG4gICAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIH0gZWxzZSBpZiAoc3RhcnQgPiBsZW4pIHtcbiAgICBzdGFydCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IDApIHtcbiAgICBlbmQgKz0gbGVuXG4gICAgaWYgKGVuZCA8IDApIGVuZCA9IDBcbiAgfSBlbHNlIGlmIChlbmQgPiBsZW4pIHtcbiAgICBlbmQgPSBsZW5cbiAgfVxuXG4gIGlmIChlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICB2YXIgbmV3QnVmXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIG5ld0J1ZiA9IEJ1ZmZlci5fYXVnbWVudCh0aGlzLnN1YmFycmF5KHN0YXJ0LCBlbmQpKVxuICB9IGVsc2Uge1xuICAgIHZhciBzbGljZUxlbiA9IGVuZCAtIHN0YXJ0XG4gICAgbmV3QnVmID0gbmV3IEJ1ZmZlcihzbGljZUxlbiwgdW5kZWZpbmVkKVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2xpY2VMZW47IGkrKykge1xuICAgICAgbmV3QnVmW2ldID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9XG5cbiAgaWYgKG5ld0J1Zi5sZW5ndGgpIG5ld0J1Zi5wYXJlbnQgPSB0aGlzLnBhcmVudCB8fCB0aGlzXG5cbiAgcmV0dXJuIG5ld0J1ZlxufVxuXG4vKlxuICogTmVlZCB0byBtYWtlIHN1cmUgdGhhdCBidWZmZXIgaXNuJ3QgdHJ5aW5nIHRvIHdyaXRlIG91dCBvZiBib3VuZHMuXG4gKi9cbmZ1bmN0aW9uIGNoZWNrT2Zmc2V0IChvZmZzZXQsIGV4dCwgbGVuZ3RoKSB7XG4gIGlmICgob2Zmc2V0ICUgMSkgIT09IDAgfHwgb2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ29mZnNldCBpcyBub3QgdWludCcpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBsZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdUcnlpbmcgdG8gYWNjZXNzIGJleW9uZCBidWZmZXIgbGVuZ3RoJylcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludExFID0gZnVuY3Rpb24gcmVhZFVJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludEJFID0gZnVuY3Rpb24gcmVhZFVJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcbiAgfVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIC0tYnl0ZUxlbmd0aF1cbiAgdmFyIG11bCA9IDFcbiAgd2hpbGUgKGJ5dGVMZW5ndGggPiAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50OCA9IGZ1bmN0aW9uIHJlYWRVSW50OCAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDEsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gdGhpc1tvZmZzZXRdXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkxFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MTZCRSA9IGZ1bmN0aW9uIHJlYWRVSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCA4KSB8IHRoaXNbb2Zmc2V0ICsgMV1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyTEUgPSBmdW5jdGlvbiByZWFkVUludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKCh0aGlzW29mZnNldF0pIHxcbiAgICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAgICh0aGlzW29mZnNldCArIDJdIDw8IDE2KSkgK1xuICAgICAgKHRoaXNbb2Zmc2V0ICsgM10gKiAweDEwMDAwMDApXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQzMkJFID0gZnVuY3Rpb24gcmVhZFVJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gKiAweDEwMDAwMDApICtcbiAgICAoKHRoaXNbb2Zmc2V0ICsgMV0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCA4KSB8XG4gICAgdGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50TEUgPSBmdW5jdGlvbiByZWFkSW50TEUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIGldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50QkUgPSBmdW5jdGlvbiByZWFkSW50QkUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgaSA9IGJ5dGVMZW5ndGhcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1pXVxuICB3aGlsZSAoaSA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50OCA9IGZ1bmN0aW9uIHJlYWRJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIGlmICghKHRoaXNbb2Zmc2V0XSAmIDB4ODApKSByZXR1cm4gKHRoaXNbb2Zmc2V0XSlcbiAgcmV0dXJuICgoMHhmZiAtIHRoaXNbb2Zmc2V0XSArIDEpICogLTEpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2TEUgPSBmdW5jdGlvbiByZWFkSW50MTZMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdIHwgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQxNkJFID0gZnVuY3Rpb24gcmVhZEludDE2QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgMV0gfCAodGhpc1tvZmZzZXRdIDw8IDgpXG4gIHJldHVybiAodmFsICYgMHg4MDAwKSA/IHZhbCB8IDB4RkZGRjAwMDAgOiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0pIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSA8PCAyNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJCRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gPDwgMjQpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRMRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdExFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRCRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdEJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCBmYWxzZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUxFID0gZnVuY3Rpb24gcmVhZERvdWJsZUxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgOCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCA1MiwgOClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlQkUgPSBmdW5jdGlvbiByZWFkRG91YmxlQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCA1MiwgOClcbn1cblxuZnVuY3Rpb24gY2hlY2tJbnQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihidWYpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdidWZmZXIgbXVzdCBiZSBhIEJ1ZmZlciBpbnN0YW5jZScpXG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3ZhbHVlIGlzIG91dCBvZiBib3VuZHMnKVxuICBpZiAob2Zmc2V0ICsgZXh0ID4gYnVmLmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB0aGlzW29mZnNldF0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50QkUgPSBmdW5jdGlvbiB3cml0ZVVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aCAtIDFcbiAgdmFyIG11bCA9IDFcbiAgdGhpc1tvZmZzZXQgKyBpXSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoLS1pID49IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50OCA9IGZ1bmN0aW9uIHdyaXRlVUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHhmZiwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkgdmFsdWUgPSBNYXRoLmZsb29yKHZhbHVlKVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQxNiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmYgKyB2YWx1ZSArIDFcbiAgZm9yICh2YXIgaSA9IDAsIGogPSBNYXRoLm1pbihidWYubGVuZ3RoIC0gb2Zmc2V0LCAyKTsgaSA8IGo7IGkrKykge1xuICAgIGJ1ZltvZmZzZXQgKyBpXSA9ICh2YWx1ZSAmICgweGZmIDw8ICg4ICogKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkpKSkgPj4+XG4gICAgICAobGl0dGxlRW5kaWFuID8gaSA6IDEgLSBpKSAqIDhcbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDE2TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4ZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQzMiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgNCk7IGkgPCBqOyBpKyspIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgPj4+IChsaXR0bGVFbmRpYW4gPyBpIDogMyAtIGkpICogOCkgJiAweGZmXG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDMyQkUgPSBmdW5jdGlvbiB3cml0ZVVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4ZmZmZmZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50TEUgPSBmdW5jdGlvbiB3cml0ZUludExFICh2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbGltaXQgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCAtIDEpXG5cbiAgICBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBsaW1pdCAtIDEsIC1saW1pdClcbiAgfVxuXG4gIHZhciBpID0gMFxuICB2YXIgbXVsID0gMVxuICB2YXIgc3ViID0gdmFsdWUgPCAwID8gMSA6IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludEJFID0gZnVuY3Rpb24gd3JpdGVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSB2YWx1ZSA8IDAgPyAxIDogMFxuICB0aGlzW29mZnNldCArIGldID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgtLWkgPj0gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAoKHZhbHVlIC8gbXVsKSA+PiAwKSAtIHN1YiAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQ4ID0gZnVuY3Rpb24gd3JpdGVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4N2YsIC0weDgwKVxuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB2YWx1ZSA9IE1hdGguZmxvb3IodmFsdWUpXG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZiArIHZhbHVlICsgMVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MTZMRSA9IGZ1bmN0aW9uIHdyaXRlSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweDdmZmYsIC0weDgwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MzJCRSA9IGZ1bmN0aW9uIHdyaXRlSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweDdmZmZmZmZmLCAtMHg4MDAwMDAwMClcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5mdW5jdGlvbiBjaGVja0lFRUU3NTQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAodmFsdWUgPiBtYXggfHwgdmFsdWUgPCBtaW4pIHRocm93IG5ldyBSYW5nZUVycm9yKCd2YWx1ZSBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxuICBpZiAob2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRmxvYXQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgNCwgMy40MDI4MjM0NjYzODUyODg2ZSszOCwgLTMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgMjMsIDQpXG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdExFID0gZnVuY3Rpb24gd3JpdGVGbG9hdExFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUZsb2F0QkUgPSBmdW5jdGlvbiB3cml0ZUZsb2F0QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZUZsb2F0KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuZnVuY3Rpb24gd3JpdGVEb3VibGUgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgOCwgMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgsIC0xLjc5NzY5MzEzNDg2MjMxNTdFKzMwOClcbiAgfVxuICBpZWVlNzU0LndyaXRlKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCA1MiwgOClcbiAgcmV0dXJuIG9mZnNldCArIDhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUxFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUsIG5vQXNzZXJ0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRG91YmxlQkUgPSBmdW5jdGlvbiB3cml0ZURvdWJsZUJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVEb3VibGUodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UsIG5vQXNzZXJ0KVxufVxuXG4vLyBjb3B5KHRhcmdldEJ1ZmZlciwgdGFyZ2V0U3RhcnQ9MCwgc291cmNlU3RhcnQ9MCwgc291cmNlRW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmNvcHkgPSBmdW5jdGlvbiBjb3B5ICh0YXJnZXQsIHRhcmdldFN0YXJ0LCBzdGFydCwgZW5kKSB7XG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCAmJiBlbmQgIT09IDApIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmICh0YXJnZXRTdGFydCA+PSB0YXJnZXQubGVuZ3RoKSB0YXJnZXRTdGFydCA9IHRhcmdldC5sZW5ndGhcbiAgaWYgKCF0YXJnZXRTdGFydCkgdGFyZ2V0U3RhcnQgPSAwXG4gIGlmIChlbmQgPiAwICYmIGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIC8vIENvcHkgMCBieXRlczsgd2UncmUgZG9uZVxuICBpZiAoZW5kID09PSBzdGFydCkgcmV0dXJuIDBcbiAgaWYgKHRhcmdldC5sZW5ndGggPT09IDAgfHwgdGhpcy5sZW5ndGggPT09IDApIHJldHVybiAwXG5cbiAgLy8gRmF0YWwgZXJyb3IgY29uZGl0aW9uc1xuICBpZiAodGFyZ2V0U3RhcnQgPCAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3RhcmdldFN0YXJ0IG91dCBvZiBib3VuZHMnKVxuICB9XG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VFbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgLy8gQXJlIHdlIG9vYj9cbiAgaWYgKGVuZCA+IHRoaXMubGVuZ3RoKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0IDwgZW5kIC0gc3RhcnQpIHtcbiAgICBlbmQgPSB0YXJnZXQubGVuZ3RoIC0gdGFyZ2V0U3RhcnQgKyBzdGFydFxuICB9XG5cbiAgdmFyIGxlbiA9IGVuZCAtIHN0YXJ0XG4gIHZhciBpXG5cbiAgaWYgKHRoaXMgPT09IHRhcmdldCAmJiBzdGFydCA8IHRhcmdldFN0YXJ0ICYmIHRhcmdldFN0YXJ0IDwgZW5kKSB7XG4gICAgLy8gZGVzY2VuZGluZyBjb3B5IGZyb20gZW5kXG4gICAgZm9yIChpID0gbGVuIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2UgaWYgKGxlbiA8IDEwMDAgfHwgIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gYXNjZW5kaW5nIGNvcHkgZnJvbSBzdGFydFxuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgdGFyZ2V0W2kgKyB0YXJnZXRTdGFydF0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGFyZ2V0Ll9zZXQodGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLCB0YXJnZXRTdGFydClcbiAgfVxuXG4gIHJldHVybiBsZW5cbn1cblxuLy8gZmlsbCh2YWx1ZSwgc3RhcnQ9MCwgZW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmZpbGwgPSBmdW5jdGlvbiBmaWxsICh2YWx1ZSwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXZhbHVlKSB2YWx1ZSA9IDBcbiAgaWYgKCFzdGFydCkgc3RhcnQgPSAwXG4gIGlmICghZW5kKSBlbmQgPSB0aGlzLmxlbmd0aFxuXG4gIGlmIChlbmQgPCBzdGFydCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2VuZCA8IHN0YXJ0JylcblxuICAvLyBGaWxsIDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVyblxuICBpZiAodGhpcy5sZW5ndGggPT09IDApIHJldHVyblxuXG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDAgfHwgZW5kID4gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdlbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgdmFyIGlcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICBmb3IgKGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgICB0aGlzW2ldID0gdmFsdWVcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFyIGJ5dGVzID0gdXRmOFRvQnl0ZXModmFsdWUudG9TdHJpbmcoKSlcbiAgICB2YXIgbGVuID0gYnl0ZXMubGVuZ3RoXG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdGhpc1tpXSA9IGJ5dGVzW2kgJSBsZW5dXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXNcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IGBBcnJheUJ1ZmZlcmAgd2l0aCB0aGUgKmNvcGllZCogbWVtb3J5IG9mIHRoZSBidWZmZXIgaW5zdGFuY2UuXG4gKiBBZGRlZCBpbiBOb2RlIDAuMTIuIE9ubHkgYXZhaWxhYmxlIGluIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCBBcnJheUJ1ZmZlci5cbiAqL1xuQnVmZmVyLnByb3RvdHlwZS50b0FycmF5QnVmZmVyID0gZnVuY3Rpb24gdG9BcnJheUJ1ZmZlciAoKSB7XG4gIGlmICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAgIHJldHVybiAobmV3IEJ1ZmZlcih0aGlzKSkuYnVmZmVyXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBidWYgPSBuZXcgVWludDhBcnJheSh0aGlzLmxlbmd0aClcbiAgICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBidWYubGVuZ3RoOyBpIDwgbGVuOyBpICs9IDEpIHtcbiAgICAgICAgYnVmW2ldID0gdGhpc1tpXVxuICAgICAgfVxuICAgICAgcmV0dXJuIGJ1Zi5idWZmZXJcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQnVmZmVyLnRvQXJyYXlCdWZmZXIgbm90IHN1cHBvcnRlZCBpbiB0aGlzIGJyb3dzZXInKVxuICB9XG59XG5cbi8vIEhFTFBFUiBGVU5DVElPTlNcbi8vID09PT09PT09PT09PT09PT1cblxudmFyIEJQID0gQnVmZmVyLnByb3RvdHlwZVxuXG4vKipcbiAqIEF1Z21lbnQgYSBVaW50OEFycmF5ICppbnN0YW5jZSogKG5vdCB0aGUgVWludDhBcnJheSBjbGFzcyEpIHdpdGggQnVmZmVyIG1ldGhvZHNcbiAqL1xuQnVmZmVyLl9hdWdtZW50ID0gZnVuY3Rpb24gX2F1Z21lbnQgKGFycikge1xuICBhcnIuY29uc3RydWN0b3IgPSBCdWZmZXJcbiAgYXJyLl9pc0J1ZmZlciA9IHRydWVcblxuICAvLyBzYXZlIHJlZmVyZW5jZSB0byBvcmlnaW5hbCBVaW50OEFycmF5IHNldCBtZXRob2QgYmVmb3JlIG92ZXJ3cml0aW5nXG4gIGFyci5fc2V0ID0gYXJyLnNldFxuXG4gIC8vIGRlcHJlY2F0ZWRcbiAgYXJyLmdldCA9IEJQLmdldFxuICBhcnIuc2V0ID0gQlAuc2V0XG5cbiAgYXJyLndyaXRlID0gQlAud3JpdGVcbiAgYXJyLnRvU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvTG9jYWxlU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvSlNPTiA9IEJQLnRvSlNPTlxuICBhcnIuZXF1YWxzID0gQlAuZXF1YWxzXG4gIGFyci5jb21wYXJlID0gQlAuY29tcGFyZVxuICBhcnIuaW5kZXhPZiA9IEJQLmluZGV4T2ZcbiAgYXJyLmNvcHkgPSBCUC5jb3B5XG4gIGFyci5zbGljZSA9IEJQLnNsaWNlXG4gIGFyci5yZWFkVUludExFID0gQlAucmVhZFVJbnRMRVxuICBhcnIucmVhZFVJbnRCRSA9IEJQLnJlYWRVSW50QkVcbiAgYXJyLnJlYWRVSW50OCA9IEJQLnJlYWRVSW50OFxuICBhcnIucmVhZFVJbnQxNkxFID0gQlAucmVhZFVJbnQxNkxFXG4gIGFyci5yZWFkVUludDE2QkUgPSBCUC5yZWFkVUludDE2QkVcbiAgYXJyLnJlYWRVSW50MzJMRSA9IEJQLnJlYWRVSW50MzJMRVxuICBhcnIucmVhZFVJbnQzMkJFID0gQlAucmVhZFVJbnQzMkJFXG4gIGFyci5yZWFkSW50TEUgPSBCUC5yZWFkSW50TEVcbiAgYXJyLnJlYWRJbnRCRSA9IEJQLnJlYWRJbnRCRVxuICBhcnIucmVhZEludDggPSBCUC5yZWFkSW50OFxuICBhcnIucmVhZEludDE2TEUgPSBCUC5yZWFkSW50MTZMRVxuICBhcnIucmVhZEludDE2QkUgPSBCUC5yZWFkSW50MTZCRVxuICBhcnIucmVhZEludDMyTEUgPSBCUC5yZWFkSW50MzJMRVxuICBhcnIucmVhZEludDMyQkUgPSBCUC5yZWFkSW50MzJCRVxuICBhcnIucmVhZEZsb2F0TEUgPSBCUC5yZWFkRmxvYXRMRVxuICBhcnIucmVhZEZsb2F0QkUgPSBCUC5yZWFkRmxvYXRCRVxuICBhcnIucmVhZERvdWJsZUxFID0gQlAucmVhZERvdWJsZUxFXG4gIGFyci5yZWFkRG91YmxlQkUgPSBCUC5yZWFkRG91YmxlQkVcbiAgYXJyLndyaXRlVUludDggPSBCUC53cml0ZVVJbnQ4XG4gIGFyci53cml0ZVVJbnRMRSA9IEJQLndyaXRlVUludExFXG4gIGFyci53cml0ZVVJbnRCRSA9IEJQLndyaXRlVUludEJFXG4gIGFyci53cml0ZVVJbnQxNkxFID0gQlAud3JpdGVVSW50MTZMRVxuICBhcnIud3JpdGVVSW50MTZCRSA9IEJQLndyaXRlVUludDE2QkVcbiAgYXJyLndyaXRlVUludDMyTEUgPSBCUC53cml0ZVVJbnQzMkxFXG4gIGFyci53cml0ZVVJbnQzMkJFID0gQlAud3JpdGVVSW50MzJCRVxuICBhcnIud3JpdGVJbnRMRSA9IEJQLndyaXRlSW50TEVcbiAgYXJyLndyaXRlSW50QkUgPSBCUC53cml0ZUludEJFXG4gIGFyci53cml0ZUludDggPSBCUC53cml0ZUludDhcbiAgYXJyLndyaXRlSW50MTZMRSA9IEJQLndyaXRlSW50MTZMRVxuICBhcnIud3JpdGVJbnQxNkJFID0gQlAud3JpdGVJbnQxNkJFXG4gIGFyci53cml0ZUludDMyTEUgPSBCUC53cml0ZUludDMyTEVcbiAgYXJyLndyaXRlSW50MzJCRSA9IEJQLndyaXRlSW50MzJCRVxuICBhcnIud3JpdGVGbG9hdExFID0gQlAud3JpdGVGbG9hdExFXG4gIGFyci53cml0ZUZsb2F0QkUgPSBCUC53cml0ZUZsb2F0QkVcbiAgYXJyLndyaXRlRG91YmxlTEUgPSBCUC53cml0ZURvdWJsZUxFXG4gIGFyci53cml0ZURvdWJsZUJFID0gQlAud3JpdGVEb3VibGVCRVxuICBhcnIuZmlsbCA9IEJQLmZpbGxcbiAgYXJyLmluc3BlY3QgPSBCUC5pbnNwZWN0XG4gIGFyci50b0FycmF5QnVmZmVyID0gQlAudG9BcnJheUJ1ZmZlclxuXG4gIHJldHVybiBhcnJcbn1cblxudmFyIElOVkFMSURfQkFTRTY0X1JFID0gL1teK1xcLzAtOUEtWmEtei1fXS9nXG5cbmZ1bmN0aW9uIGJhc2U2NGNsZWFuIChzdHIpIHtcbiAgLy8gTm9kZSBzdHJpcHMgb3V0IGludmFsaWQgY2hhcmFjdGVycyBsaWtlIFxcbiBhbmQgXFx0IGZyb20gdGhlIHN0cmluZywgYmFzZTY0LWpzIGRvZXMgbm90XG4gIHN0ciA9IHN0cmluZ3RyaW0oc3RyKS5yZXBsYWNlKElOVkFMSURfQkFTRTY0X1JFLCAnJylcbiAgLy8gTm9kZSBjb252ZXJ0cyBzdHJpbmdzIHdpdGggbGVuZ3RoIDwgMiB0byAnJ1xuICBpZiAoc3RyLmxlbmd0aCA8IDIpIHJldHVybiAnJ1xuICAvLyBOb2RlIGFsbG93cyBmb3Igbm9uLXBhZGRlZCBiYXNlNjQgc3RyaW5ncyAobWlzc2luZyB0cmFpbGluZyA9PT0pLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgd2hpbGUgKHN0ci5sZW5ndGggJSA0ICE9PSAwKSB7XG4gICAgc3RyID0gc3RyICsgJz0nXG4gIH1cbiAgcmV0dXJuIHN0clxufVxuXG5mdW5jdGlvbiBzdHJpbmd0cmltIChzdHIpIHtcbiAgaWYgKHN0ci50cmltKSByZXR1cm4gc3RyLnRyaW0oKVxuICByZXR1cm4gc3RyLnJlcGxhY2UoL15cXHMrfFxccyskL2csICcnKVxufVxuXG5mdW5jdGlvbiB0b0hleCAobikge1xuICBpZiAobiA8IDE2KSByZXR1cm4gJzAnICsgbi50b1N0cmluZygxNilcbiAgcmV0dXJuIG4udG9TdHJpbmcoMTYpXG59XG5cbmZ1bmN0aW9uIHV0ZjhUb0J5dGVzIChzdHJpbmcsIHVuaXRzKSB7XG4gIHVuaXRzID0gdW5pdHMgfHwgSW5maW5pdHlcbiAgdmFyIGNvZGVQb2ludFxuICB2YXIgbGVuZ3RoID0gc3RyaW5nLmxlbmd0aFxuICB2YXIgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcbiAgdmFyIGJ5dGVzID0gW11cblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgY29kZVBvaW50ID0gc3RyaW5nLmNoYXJDb2RlQXQoaSlcblxuICAgIC8vIGlzIHN1cnJvZ2F0ZSBjb21wb25lbnRcbiAgICBpZiAoY29kZVBvaW50ID4gMHhEN0ZGICYmIGNvZGVQb2ludCA8IDB4RTAwMCkge1xuICAgICAgLy8gbGFzdCBjaGFyIHdhcyBhIGxlYWRcbiAgICAgIGlmICghbGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgICAvLyBubyBsZWFkIHlldFxuICAgICAgICBpZiAoY29kZVBvaW50ID4gMHhEQkZGKSB7XG4gICAgICAgICAgLy8gdW5leHBlY3RlZCB0cmFpbFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH0gZWxzZSBpZiAoaSArIDEgPT09IGxlbmd0aCkge1xuICAgICAgICAgIC8vIHVucGFpcmVkIGxlYWRcbiAgICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gdmFsaWQgbGVhZFxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG5cbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gMiBsZWFkcyBpbiBhIHJvd1xuICAgICAgaWYgKGNvZGVQb2ludCA8IDB4REMwMCkge1xuICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgbGVhZFN1cnJvZ2F0ZSA9IGNvZGVQb2ludFxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyB2YWxpZCBzdXJyb2dhdGUgcGFpclxuICAgICAgY29kZVBvaW50ID0gKGxlYWRTdXJyb2dhdGUgLSAweEQ4MDAgPDwgMTAgfCBjb2RlUG9pbnQgLSAweERDMDApICsgMHgxMDAwMFxuICAgIH0gZWxzZSBpZiAobGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgLy8gdmFsaWQgYm1wIGNoYXIsIGJ1dCBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgfVxuXG4gICAgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcblxuICAgIC8vIGVuY29kZSB1dGY4XG4gICAgaWYgKGNvZGVQb2ludCA8IDB4ODApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMSkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChjb2RlUG9pbnQpXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDgwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAyKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2IHwgMHhDMCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMykgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyB8IDB4RTAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDQpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDEyIHwgMHhGMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2ICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjb2RlIHBvaW50JylcbiAgICB9XG4gIH1cblxuICByZXR1cm4gYnl0ZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlUb0J5dGVzIChzdHIpIHtcbiAgdmFyIGJ5dGVBcnJheSA9IFtdXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgLy8gTm9kZSdzIGNvZGUgc2VlbXMgdG8gYmUgZG9pbmcgdGhpcyBhbmQgbm90ICYgMHg3Ri4uXG4gICAgYnl0ZUFycmF5LnB1c2goc3RyLmNoYXJDb2RlQXQoaSkgJiAweEZGKVxuICB9XG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gdXRmMTZsZVRvQnl0ZXMgKHN0ciwgdW5pdHMpIHtcbiAgdmFyIGMsIGhpLCBsb1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcblxuICAgIGMgPSBzdHIuY2hhckNvZGVBdChpKVxuICAgIGhpID0gYyA+PiA4XG4gICAgbG8gPSBjICUgMjU2XG4gICAgYnl0ZUFycmF5LnB1c2gobG8pXG4gICAgYnl0ZUFycmF5LnB1c2goaGkpXG4gIH1cblxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIGJhc2U2NFRvQnl0ZXMgKHN0cikge1xuICByZXR1cm4gYmFzZTY0LnRvQnl0ZUFycmF5KGJhc2U2NGNsZWFuKHN0cikpXG59XG5cbmZ1bmN0aW9uIGJsaXRCdWZmZXIgKHNyYywgZHN0LCBvZmZzZXQsIGxlbmd0aCkge1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKChpICsgb2Zmc2V0ID49IGRzdC5sZW5ndGgpIHx8IChpID49IHNyYy5sZW5ndGgpKSBicmVha1xuICAgIGRzdFtpICsgb2Zmc2V0XSA9IHNyY1tpXVxuICB9XG4gIHJldHVybiBpXG59XG4iLCJ2YXIgbG9va3VwID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky8nO1xuXG47KGZ1bmN0aW9uIChleHBvcnRzKSB7XG5cdCd1c2Ugc3RyaWN0JztcblxuICB2YXIgQXJyID0gKHR5cGVvZiBVaW50OEFycmF5ICE9PSAndW5kZWZpbmVkJylcbiAgICA/IFVpbnQ4QXJyYXlcbiAgICA6IEFycmF5XG5cblx0dmFyIFBMVVMgICA9ICcrJy5jaGFyQ29kZUF0KDApXG5cdHZhciBTTEFTSCAgPSAnLycuY2hhckNvZGVBdCgwKVxuXHR2YXIgTlVNQkVSID0gJzAnLmNoYXJDb2RlQXQoMClcblx0dmFyIExPV0VSICA9ICdhJy5jaGFyQ29kZUF0KDApXG5cdHZhciBVUFBFUiAgPSAnQScuY2hhckNvZGVBdCgwKVxuXHR2YXIgUExVU19VUkxfU0FGRSA9ICctJy5jaGFyQ29kZUF0KDApXG5cdHZhciBTTEFTSF9VUkxfU0FGRSA9ICdfJy5jaGFyQ29kZUF0KDApXG5cblx0ZnVuY3Rpb24gZGVjb2RlIChlbHQpIHtcblx0XHR2YXIgY29kZSA9IGVsdC5jaGFyQ29kZUF0KDApXG5cdFx0aWYgKGNvZGUgPT09IFBMVVMgfHxcblx0XHQgICAgY29kZSA9PT0gUExVU19VUkxfU0FGRSlcblx0XHRcdHJldHVybiA2MiAvLyAnKydcblx0XHRpZiAoY29kZSA9PT0gU0xBU0ggfHxcblx0XHQgICAgY29kZSA9PT0gU0xBU0hfVVJMX1NBRkUpXG5cdFx0XHRyZXR1cm4gNjMgLy8gJy8nXG5cdFx0aWYgKGNvZGUgPCBOVU1CRVIpXG5cdFx0XHRyZXR1cm4gLTEgLy9ubyBtYXRjaFxuXHRcdGlmIChjb2RlIDwgTlVNQkVSICsgMTApXG5cdFx0XHRyZXR1cm4gY29kZSAtIE5VTUJFUiArIDI2ICsgMjZcblx0XHRpZiAoY29kZSA8IFVQUEVSICsgMjYpXG5cdFx0XHRyZXR1cm4gY29kZSAtIFVQUEVSXG5cdFx0aWYgKGNvZGUgPCBMT1dFUiArIDI2KVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBMT1dFUiArIDI2XG5cdH1cblxuXHRmdW5jdGlvbiBiNjRUb0J5dGVBcnJheSAoYjY0KSB7XG5cdFx0dmFyIGksIGosIGwsIHRtcCwgcGxhY2VIb2xkZXJzLCBhcnJcblxuXHRcdGlmIChiNjQubGVuZ3RoICUgNCA+IDApIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzdHJpbmcuIExlbmd0aCBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgNCcpXG5cdFx0fVxuXG5cdFx0Ly8gdGhlIG51bWJlciBvZiBlcXVhbCBzaWducyAocGxhY2UgaG9sZGVycylcblx0XHQvLyBpZiB0aGVyZSBhcmUgdHdvIHBsYWNlaG9sZGVycywgdGhhbiB0aGUgdHdvIGNoYXJhY3RlcnMgYmVmb3JlIGl0XG5cdFx0Ly8gcmVwcmVzZW50IG9uZSBieXRlXG5cdFx0Ly8gaWYgdGhlcmUgaXMgb25seSBvbmUsIHRoZW4gdGhlIHRocmVlIGNoYXJhY3RlcnMgYmVmb3JlIGl0IHJlcHJlc2VudCAyIGJ5dGVzXG5cdFx0Ly8gdGhpcyBpcyBqdXN0IGEgY2hlYXAgaGFjayB0byBub3QgZG8gaW5kZXhPZiB0d2ljZVxuXHRcdHZhciBsZW4gPSBiNjQubGVuZ3RoXG5cdFx0cGxhY2VIb2xkZXJzID0gJz0nID09PSBiNjQuY2hhckF0KGxlbiAtIDIpID8gMiA6ICc9JyA9PT0gYjY0LmNoYXJBdChsZW4gLSAxKSA/IDEgOiAwXG5cblx0XHQvLyBiYXNlNjQgaXMgNC8zICsgdXAgdG8gdHdvIGNoYXJhY3RlcnMgb2YgdGhlIG9yaWdpbmFsIGRhdGFcblx0XHRhcnIgPSBuZXcgQXJyKGI2NC5sZW5ndGggKiAzIC8gNCAtIHBsYWNlSG9sZGVycylcblxuXHRcdC8vIGlmIHRoZXJlIGFyZSBwbGFjZWhvbGRlcnMsIG9ubHkgZ2V0IHVwIHRvIHRoZSBsYXN0IGNvbXBsZXRlIDQgY2hhcnNcblx0XHRsID0gcGxhY2VIb2xkZXJzID4gMCA/IGI2NC5sZW5ndGggLSA0IDogYjY0Lmxlbmd0aFxuXG5cdFx0dmFyIEwgPSAwXG5cblx0XHRmdW5jdGlvbiBwdXNoICh2KSB7XG5cdFx0XHRhcnJbTCsrXSA9IHZcblx0XHR9XG5cblx0XHRmb3IgKGkgPSAwLCBqID0gMDsgaSA8IGw7IGkgKz0gNCwgaiArPSAzKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDE4KSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDEyKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMikpIDw8IDYpIHwgZGVjb2RlKGI2NC5jaGFyQXQoaSArIDMpKVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwMDApID4+IDE2KVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwKSA+PiA4KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH1cblxuXHRcdGlmIChwbGFjZUhvbGRlcnMgPT09IDIpIHtcblx0XHRcdHRtcCA9IChkZWNvZGUoYjY0LmNoYXJBdChpKSkgPDwgMikgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA+PiA0KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH0gZWxzZSBpZiAocGxhY2VIb2xkZXJzID09PSAxKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDEwKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDQpIHwgKGRlY29kZShiNjQuY2hhckF0KGkgKyAyKSkgPj4gMilcblx0XHRcdHB1c2goKHRtcCA+PiA4KSAmIDB4RkYpXG5cdFx0XHRwdXNoKHRtcCAmIDB4RkYpXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGFyclxuXHR9XG5cblx0ZnVuY3Rpb24gdWludDhUb0Jhc2U2NCAodWludDgpIHtcblx0XHR2YXIgaSxcblx0XHRcdGV4dHJhQnl0ZXMgPSB1aW50OC5sZW5ndGggJSAzLCAvLyBpZiB3ZSBoYXZlIDEgYnl0ZSBsZWZ0LCBwYWQgMiBieXRlc1xuXHRcdFx0b3V0cHV0ID0gXCJcIixcblx0XHRcdHRlbXAsIGxlbmd0aFxuXG5cdFx0ZnVuY3Rpb24gZW5jb2RlIChudW0pIHtcblx0XHRcdHJldHVybiBsb29rdXAuY2hhckF0KG51bSlcblx0XHR9XG5cblx0XHRmdW5jdGlvbiB0cmlwbGV0VG9CYXNlNjQgKG51bSkge1xuXHRcdFx0cmV0dXJuIGVuY29kZShudW0gPj4gMTggJiAweDNGKSArIGVuY29kZShudW0gPj4gMTIgJiAweDNGKSArIGVuY29kZShudW0gPj4gNiAmIDB4M0YpICsgZW5jb2RlKG51bSAmIDB4M0YpXG5cdFx0fVxuXG5cdFx0Ly8gZ28gdGhyb3VnaCB0aGUgYXJyYXkgZXZlcnkgdGhyZWUgYnl0ZXMsIHdlJ2xsIGRlYWwgd2l0aCB0cmFpbGluZyBzdHVmZiBsYXRlclxuXHRcdGZvciAoaSA9IDAsIGxlbmd0aCA9IHVpbnQ4Lmxlbmd0aCAtIGV4dHJhQnl0ZXM7IGkgPCBsZW5ndGg7IGkgKz0gMykge1xuXHRcdFx0dGVtcCA9ICh1aW50OFtpXSA8PCAxNikgKyAodWludDhbaSArIDFdIDw8IDgpICsgKHVpbnQ4W2kgKyAyXSlcblx0XHRcdG91dHB1dCArPSB0cmlwbGV0VG9CYXNlNjQodGVtcClcblx0XHR9XG5cblx0XHQvLyBwYWQgdGhlIGVuZCB3aXRoIHplcm9zLCBidXQgbWFrZSBzdXJlIHRvIG5vdCBmb3JnZXQgdGhlIGV4dHJhIGJ5dGVzXG5cdFx0c3dpdGNoIChleHRyYUJ5dGVzKSB7XG5cdFx0XHRjYXNlIDE6XG5cdFx0XHRcdHRlbXAgPSB1aW50OFt1aW50OC5sZW5ndGggLSAxXVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKHRlbXAgPj4gMilcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA8PCA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSAnPT0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0XHRjYXNlIDI6XG5cdFx0XHRcdHRlbXAgPSAodWludDhbdWludDgubGVuZ3RoIC0gMl0gPDwgOCkgKyAodWludDhbdWludDgubGVuZ3RoIC0gMV0pXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUodGVtcCA+PiAxMClcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA+PiA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPDwgMikgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gJz0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG91dHB1dFxuXHR9XG5cblx0ZXhwb3J0cy50b0J5dGVBcnJheSA9IGI2NFRvQnl0ZUFycmF5XG5cdGV4cG9ydHMuZnJvbUJ5dGVBcnJheSA9IHVpbnQ4VG9CYXNlNjRcbn0odHlwZW9mIGV4cG9ydHMgPT09ICd1bmRlZmluZWQnID8gKHRoaXMuYmFzZTY0anMgPSB7fSkgOiBleHBvcnRzKSlcbiIsImV4cG9ydHMucmVhZCA9IGZ1bmN0aW9uIChidWZmZXIsIG9mZnNldCwgaXNMRSwgbUxlbiwgbkJ5dGVzKSB7XG4gIHZhciBlLCBtXG4gIHZhciBlTGVuID0gbkJ5dGVzICogOCAtIG1MZW4gLSAxXG4gIHZhciBlTWF4ID0gKDEgPDwgZUxlbikgLSAxXG4gIHZhciBlQmlhcyA9IGVNYXggPj4gMVxuICB2YXIgbkJpdHMgPSAtN1xuICB2YXIgaSA9IGlzTEUgPyAobkJ5dGVzIC0gMSkgOiAwXG4gIHZhciBkID0gaXNMRSA/IC0xIDogMVxuICB2YXIgcyA9IGJ1ZmZlcltvZmZzZXQgKyBpXVxuXG4gIGkgKz0gZFxuXG4gIGUgPSBzICYgKCgxIDw8ICgtbkJpdHMpKSAtIDEpXG4gIHMgPj49ICgtbkJpdHMpXG4gIG5CaXRzICs9IGVMZW5cbiAgZm9yICg7IG5CaXRzID4gMDsgZSA9IGUgKiAyNTYgKyBidWZmZXJbb2Zmc2V0ICsgaV0sIGkgKz0gZCwgbkJpdHMgLT0gOCkge31cblxuICBtID0gZSAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBlID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBtTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IG0gPSBtICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgaWYgKGUgPT09IDApIHtcbiAgICBlID0gMSAtIGVCaWFzXG4gIH0gZWxzZSBpZiAoZSA9PT0gZU1heCkge1xuICAgIHJldHVybiBtID8gTmFOIDogKChzID8gLTEgOiAxKSAqIEluZmluaXR5KVxuICB9IGVsc2Uge1xuICAgIG0gPSBtICsgTWF0aC5wb3coMiwgbUxlbilcbiAgICBlID0gZSAtIGVCaWFzXG4gIH1cbiAgcmV0dXJuIChzID8gLTEgOiAxKSAqIG0gKiBNYXRoLnBvdygyLCBlIC0gbUxlbilcbn1cblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uIChidWZmZXIsIHZhbHVlLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbSwgY1xuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIHJ0ID0gKG1MZW4gPT09IDIzID8gTWF0aC5wb3coMiwgLTI0KSAtIE1hdGgucG93KDIsIC03NykgOiAwKVxuICB2YXIgaSA9IGlzTEUgPyAwIDogKG5CeXRlcyAtIDEpXG4gIHZhciBkID0gaXNMRSA/IDEgOiAtMVxuICB2YXIgcyA9IHZhbHVlIDwgMCB8fCAodmFsdWUgPT09IDAgJiYgMSAvIHZhbHVlIDwgMCkgPyAxIDogMFxuXG4gIHZhbHVlID0gTWF0aC5hYnModmFsdWUpXG5cbiAgaWYgKGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICBtID0gaXNOYU4odmFsdWUpID8gMSA6IDBcbiAgICBlID0gZU1heFxuICB9IGVsc2Uge1xuICAgIGUgPSBNYXRoLmZsb29yKE1hdGgubG9nKHZhbHVlKSAvIE1hdGguTE4yKVxuICAgIGlmICh2YWx1ZSAqIChjID0gTWF0aC5wb3coMiwgLWUpKSA8IDEpIHtcbiAgICAgIGUtLVxuICAgICAgYyAqPSAyXG4gICAgfVxuICAgIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgdmFsdWUgKz0gcnQgLyBjXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbHVlICs9IHJ0ICogTWF0aC5wb3coMiwgMSAtIGVCaWFzKVxuICAgIH1cbiAgICBpZiAodmFsdWUgKiBjID49IDIpIHtcbiAgICAgIGUrK1xuICAgICAgYyAvPSAyXG4gICAgfVxuXG4gICAgaWYgKGUgKyBlQmlhcyA+PSBlTWF4KSB7XG4gICAgICBtID0gMFxuICAgICAgZSA9IGVNYXhcbiAgICB9IGVsc2UgaWYgKGUgKyBlQmlhcyA+PSAxKSB7XG4gICAgICBtID0gKHZhbHVlICogYyAtIDEpICogTWF0aC5wb3coMiwgbUxlbilcbiAgICAgIGUgPSBlICsgZUJpYXNcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IHZhbHVlICogTWF0aC5wb3coMiwgZUJpYXMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gMFxuICAgIH1cbiAgfVxuXG4gIGZvciAoOyBtTGVuID49IDg7IGJ1ZmZlcltvZmZzZXQgKyBpXSA9IG0gJiAweGZmLCBpICs9IGQsIG0gLz0gMjU2LCBtTGVuIC09IDgpIHt9XG5cbiAgZSA9IChlIDw8IG1MZW4pIHwgbVxuICBlTGVuICs9IG1MZW5cbiAgZm9yICg7IGVMZW4gPiAwOyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBlICYgMHhmZiwgaSArPSBkLCBlIC89IDI1NiwgZUxlbiAtPSA4KSB7fVxuXG4gIGJ1ZmZlcltvZmZzZXQgKyBpIC0gZF0gfD0gcyAqIDEyOFxufVxuIiwiXG4vKipcbiAqIGlzQXJyYXlcbiAqL1xuXG52YXIgaXNBcnJheSA9IEFycmF5LmlzQXJyYXk7XG5cbi8qKlxuICogdG9TdHJpbmdcbiAqL1xuXG52YXIgc3RyID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztcblxuLyoqXG4gKiBXaGV0aGVyIG9yIG5vdCB0aGUgZ2l2ZW4gYHZhbGBcbiAqIGlzIGFuIGFycmF5LlxuICpcbiAqIGV4YW1wbGU6XG4gKlxuICogICAgICAgIGlzQXJyYXkoW10pO1xuICogICAgICAgIC8vID4gdHJ1ZVxuICogICAgICAgIGlzQXJyYXkoYXJndW1lbnRzKTtcbiAqICAgICAgICAvLyA+IGZhbHNlXG4gKiAgICAgICAgaXNBcnJheSgnJyk7XG4gKiAgICAgICAgLy8gPiBmYWxzZVxuICpcbiAqIEBwYXJhbSB7bWl4ZWR9IHZhbFxuICogQHJldHVybiB7Ym9vbH1cbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGlzQXJyYXkgfHwgZnVuY3Rpb24gKHZhbCkge1xuICByZXR1cm4gISEgdmFsICYmICdbb2JqZWN0IEFycmF5XScgPT0gc3RyLmNhbGwodmFsKTtcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJ2ZXJzaW9uXCI6IFwiXCJcbn1cbiIsIi8qKlxuICogRXBpY2VudGVyIEphdmFzY3JpcHQgbGlicmFyaWVzXG4gKiB2PCU9IHZlcnNpb24gJT5cbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9mb3Jpby9lcGljZW50ZXItanMtbGlic1xuICovXG5cbnZhciBGID0ge1xuICAgIHV0aWw6IHt9LFxuICAgIGZhY3Rvcnk6IHt9LFxuICAgIHRyYW5zcG9ydDoge30sXG4gICAgc3RvcmU6IHt9LFxuICAgIHNlcnZpY2U6IHt9LFxuICAgIG1hbmFnZXI6IHtcbiAgICAgICAgc3RyYXRlZ3k6IHt9XG4gICAgfSxcblxufTtcblxuRi51dGlsLnF1ZXJ5ID0gcmVxdWlyZSgnLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbkYudXRpbC5tYWtlU2VxdWVuY2UgPSByZXF1aXJlKCcuL3V0aWwvbWFrZS1zZXF1ZW5jZScpO1xuRi51dGlsLnJ1biA9IHJlcXVpcmUoJy4vdXRpbC9ydW4tdXRpbCcpO1xuRi51dGlsLmNsYXNzRnJvbSA9IHJlcXVpcmUoJy4vdXRpbC9pbmhlcml0Jyk7XG5cbkYuZmFjdG9yeS5UcmFuc3BvcnQgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5GLnRyYW5zcG9ydC5BamF4ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvYWpheC1odHRwLXRyYW5zcG9ydCcpO1xuXG5GLnNlcnZpY2UuVVJMID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xuRi5zZXJ2aWNlLkNvbmZpZyA9IHJlcXVpcmUoJy4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbkYuc2VydmljZS5SdW4gPSByZXF1aXJlKCcuL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRmlsZSA9IHJlcXVpcmUoJy4vc2VydmljZS9hZG1pbi1maWxlLXNlcnZpY2UnKTtcbkYuc2VydmljZS5WYXJpYWJsZXMgPSByZXF1aXJlKCcuL3NlcnZpY2UvdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRGF0YSA9IHJlcXVpcmUoJy4vc2VydmljZS9kYXRhLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuQXV0aCA9IHJlcXVpcmUoJy4vc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuV29ybGQgPSByZXF1aXJlKCcuL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5TdGF0ZSA9IHJlcXVpcmUoJy4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLlVzZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLk1lbWJlciA9IHJlcXVpcmUoJy4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Bc3NldCA9IHJlcXVpcmUoJy4vc2VydmljZS9hc3NldC1hcGktYWRhcHRlcicpO1xuXG5GLnN0b3JlLkNvb2tpZSA9IHJlcXVpcmUoJy4vc3RvcmUvY29va2llLXN0b3JlJyk7XG5GLmZhY3RvcnkuU3RvcmUgPSByZXF1aXJlKCcuL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcblxuRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvc2NlbmFyaW8tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLlJ1bk1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2F1dGgtbWFuYWdlcicpO1xuRi5tYW5hZ2VyLldvcmxkTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvd29ybGQtbWFuYWdlcicpO1xuXG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ2Fsd2F5cy1uZXcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvYWx3YXlzLW5ldy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5Wydjb25kaXRpb25hbC1jcmVhdGlvbiddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5LmlkZW50aXR5ID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9pZGVudGl0eS1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtcGVyc2lzdGVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLWluaXRpYWxpemVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpO1xuXG5GLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXInKTtcbkYuc2VydmljZS5DaGFubmVsID0gcmVxdWlyZSgnLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xuXG5GLnZlcnNpb24gPSAnPCU9IHZlcnNpb24gJT4nO1xuRi5hcGkgPSByZXF1aXJlKCcuL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuZ2xvYmFsLkYgPSBGO1xubW9kdWxlLmV4cG9ydHMgPSBGO1xuIiwiLyoqXG4qICMjIEF1dGhvcml6YXRpb24gTWFuYWdlclxuKlxuKiBUaGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIG1hbmFnZSB1c2VyIGF1dGhlbnRpY2F0aW9uIChsb2dnaW5nIGluIGFuZCBvdXQpIGFuZCBhdXRob3JpemF0aW9uIChrZWVwaW5nIHRyYWNrIG9mIHRva2Vucywgc2Vzc2lvbnMsIGFuZCBncm91cHMpIGZvciBwcm9qZWN0cy5cbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBpcyBtb3N0IHVzZWZ1bCBmb3IgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSB3aXRoIGFuIGFjY2VzcyBsZXZlbCBvZiBbQXV0aGVudGljYXRlZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2FjY2VzcykuIFRoZXNlIHByb2plY3RzIGFyZSBhY2Nlc3NlZCBieSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiBvbmUgb3IgbW9yZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS5cbipcbiogIyMjI1VzaW5nIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXJcbipcbiogVG8gdXNlIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZDpcbipcbiogICAgICAgdmFyIGF1dGhNZ3IgPSBuZXcgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKHtcbiogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgIHVzZXJOYW1lOiAnZW5kdXNlcjEnLFxuKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiogICAgICAgfSk7XG4qICAgICAgIGF1dGhNZ3IubG9naW4oKS50aGVuKGZ1bmN0aW9uICgpIHtcbiogICAgICAgICAgIGF1dGhNZ3IuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuKiAgICAgICB9KTtcbipcbipcbiogVGhlIGBvcHRpb25zYCBvYmplY3QgcGFzc2VkIHRvIHRoZSBgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKClgIGNhbGwgY2FuIGluY2x1ZGU6XG4qXG4qICAgKiBgYWNjb3VudGA6IFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICogYHVzZXJOYW1lYDogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLlxuKiAgICogYHBhc3N3b3JkYDogUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLlxuKiAgICogYHByb2plY3RgOiBUaGUgKipQcm9qZWN0IElEKiogZm9yIHRoZSBwcm9qZWN0IHRvIGxvZyB0aGlzIHVzZXIgaW50by4gT3B0aW9uYWwuXG4qICAgKiBgZ3JvdXBJZGA6IElkIG9mIHRoZSBncm91cCB0byB3aGljaCBgdXNlck5hbWVgIGJlbG9uZ3MuIFJlcXVpcmVkIGZvciBlbmQgdXNlcnMgaWYgdGhlIGBwcm9qZWN0YCBpcyBzcGVjaWZpZWQuXG4qXG4qIElmIHlvdSBwcmVmZXIgc3RhcnRpbmcgZnJvbSBhIHRlbXBsYXRlLCB0aGUgRXBpY2VudGVyIEpTIExpYnMgW0xvZ2luIENvbXBvbmVudF0oLi4vLi4vI2NvbXBvbmVudHMpIHVzZXMgdGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBhcyB3ZWxsLiBUaGlzIHNhbXBsZSBIVE1MIHBhZ2UgKGFuZCBhc3NvY2lhdGVkIENTUyBhbmQgSlMgZmlsZXMpIHByb3ZpZGVzIGEgbG9naW4gZm9ybSBmb3IgdGVhbSBtZW1iZXJzIGFuZCBlbmQgdXNlcnMgb2YgeW91ciBwcm9qZWN0LiBJdCBhbHNvIGluY2x1ZGVzIGEgZ3JvdXAgc2VsZWN0b3IgZm9yIGVuZCB1c2VycyB0aGF0IGFyZSBtZW1iZXJzIG9mIG11bHRpcGxlIGdyb3Vwcy5cbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBBdXRoQWRhcHRlciA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xudmFyIE1lbWJlckFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlcicpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIEJ1ZmZlciA9IHJlcXVpcmUoJ2J1ZmZlcicpLkJ1ZmZlcjtcbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4va2V5LW5hbWVzJyk7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBXaGVyZSB0byBzdG9yZSB1c2VyIGFjY2VzcyB0b2tlbnMgZm9yIHRlbXBvcmFyeSBhY2Nlc3MuIERlZmF1bHRzIHRvIHN0b3JpbmcgaW4gYSBjb29raWUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBzdG9yZTogeyBzeW5jaHJvbm91czogdHJ1ZSB9XG59O1xuXG52YXIgRVBJX0NPT0tJRV9LRVkgPSBrZXlOYW1lcy5FUElfQ09PS0lFX0tFWTtcbnZhciBFUElfU0VTU0lPTl9LRVkgPSBrZXlOYW1lcy5FUElfU0VTU0lPTl9LRVk7XG52YXIgc3RvcmU7XG52YXIgdG9rZW47XG52YXIgc2Vzc2lvbjtcblxuZnVuY3Rpb24gc2F2ZVNlc3Npb24odXNlckluZm8pIHtcbiAgICB2YXIgc2VyaWFsaXplZCA9IEpTT04uc3RyaW5naWZ5KHVzZXJJbmZvKTtcbiAgICBzdG9yZS5zZXQoRVBJX1NFU1NJT05fS0VZLCBzZXJpYWxpemVkKTtcblxuICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAvL2pzY3M6ZGlzYWJsZVxuICAgIHN0b3JlLnNldChFUElfQ09PS0lFX0tFWSwgdXNlckluZm8uYXV0aF90b2tlbik7XG59XG5cbmZ1bmN0aW9uIGdldFNlc3Npb24oKSB7XG4gICAgdmFyIHNlc3Npb24gPSBzdG9yZS5nZXQoRVBJX1NFU1NJT05fS0VZKSB8fCAne30nO1xuICAgIHJldHVybiBKU09OLnBhcnNlKHNlc3Npb24pO1xufVxuXG5mdW5jdGlvbiBBdXRoTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZSh0aGlzLm9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB0aGlzLm9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICAvLyBudWxsIG1pZ2h0IHNwZWNpZmllZCB0byBkaXNhYmxlIHByb2plY3QgZmlsdGVyaW5nXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wcm9qZWN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICBzZXNzaW9uID0gZ2V0U2Vzc2lvbigpO1xuICAgIHRva2VuID0gc3RvcmUuZ2V0KEVQSV9DT09LSUVfS0VZKSB8fCAnJztcbiAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgLy9qc2NzOmRpc2FibGVcbiAgICB0aGlzLmF1dGhBZGFwdGVyID0gbmV3IEF1dGhBZGFwdGVyKHRoaXMub3B0aW9ucywgeyB0b2tlbjogc2Vzc2lvbi5hdXRoX3Rva2VuIH0pO1xufVxuXG52YXIgX2ZpbmRVc2VySW5Hcm91cCA9IGZ1bmN0aW9uIChtZW1iZXJzLCBpZCkge1xuICAgIGZvciAodmFyIGogPSAwOyBqPG1lbWJlcnMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKG1lbWJlcnNbal0udXNlcklkID09PSBpZCkge1xuICAgICAgICAgICAgcmV0dXJuIG1lbWJlcnNbal07XG4gICAgICAgIH1cbiAgICB9XG5cblxuICAgIHJldHVybiBudWxsO1xufTtcblxuQXV0aE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQXV0aE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAqIExvZ3MgdXNlciBpbi5cbiAgICAqXG4gICAgKiAqKkV4YW1wbGUqKlxuICAgICpcbiAgICAqICAgICAgIGF1dGhNZ3IubG9naW4oe1xuICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLCBcbiAgICAqICAgICAgICAgICB1c2VyTmFtZTogJ2VuZHVzZXIxJyxcbiAgICAqICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyBcbiAgICAqICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gZXhhY3RseSBvbmUgZ3JvdXBcbiAgICAqICAgICAgICAgICAgICAgLy8gKG9yIGlmIHRoZSBsb2dpbigpIGNhbGwgaXMgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGUgZ3JvdXAgaWQpXG4gICAgKiAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIGhlcmVcbiAgICAqICAgICAgICAgICB9KVxuICAgICogICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIG11bHRpcGxlIGdyb3VwcywgXG4gICAgKiAgICAgICAgICAgICAgIC8vIHRoZSBsb2dpbigpIGNhbGwgZmFpbHMgXG4gICAgKiAgICAgICAgICAgICAgIC8vIGFuZCByZXR1cm5zIGFsbCBncm91cHMgb2Ygd2hpY2ggdGhlIHVzZXIgaXMgYSBtZW1iZXJcbiAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpIDwgc3RhdHVzT2JqLnVzZXJHcm91cHMubGVuZ3RoOyBpKyspIHtcbiAgICAqICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHN0YXR1c09iai51c2VyR3JvdXBzW2ldLm5hbWUsIHN0YXR1c09iai51c2VyR3JvdXBzW2ldLmdyb3VwSWQpO1xuICAgICogICAgICAgICAgICAgICB9XG4gICAgKiAgICAgICAgICAgfSk7XG4gICAgKlxuICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAqXG4gICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuIElmIG5vdCBwYXNzZWQgaW4gd2hlbiBjcmVhdGluZyBhbiBpbnN0YW5jZSBvZiB0aGUgbWFuYWdlciAoYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCksIHRoZXNlIG9wdGlvbnMgc2hvdWxkIGluY2x1ZGU6IFxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmFjY291bnRgIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnVzZXJOYW1lYCBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMucGFzc3dvcmRgIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5wcm9qZWN0YCAoT3B0aW9uYWwpIFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhlIHByb2plY3QgdG8gbG9nIHRoaXMgdXNlciBpbnRvLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpZiB0aGUgYHByb2plY3RgIGlzIHNwZWNpZmllZCBhbmQgaWYgdGhlIGVuZCB1c2VycyBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3RoZXJ3aXNlIG9wdGlvbmFsLiBcbiAgICAqL1xuICAgIGxvZ2luOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHsgc3VjY2VzczogJC5ub29wLCBlcnJvcjogJC5ub29wIH0sIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgIHZhciBvdXRTdWNjZXNzID0gYWRhcHRlck9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgdmFyIG91dEVycm9yID0gYWRhcHRlck9wdGlvbnMuZXJyb3I7XG4gICAgICAgIHZhciBncm91cElkID0gYWRhcHRlck9wdGlvbnMuZ3JvdXBJZDtcblxuICAgICAgICB2YXIgZGVjb2RlVG9rZW4gPSBmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgICAgIHZhciBlbmNvZGVkID0gdG9rZW4uc3BsaXQoJy4nKVsxXTtcbiAgICAgICAgICAgIHdoaWxlIChlbmNvZGVkLmxlbmd0aCAlIDQgIT09IDApIHtcbiAgICAgICAgICAgICAgICBlbmNvZGVkICs9ICc9JztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGRlY29kZSA9IHdpbmRvdy5hdG9iID8gd2luZG93LmF0b2IgOiBmdW5jdGlvbiAoZW5jb2RlZCkgeyByZXR1cm4gbmV3IEJ1ZmZlcihlbmNvZGVkLCAnYmFzZTY0JykudG9TdHJpbmcoJ2FzY2lpJyk7IH07XG5cbiAgICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGRlY29kZShlbmNvZGVkKSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZUdyb3VwRXJyb3IgPSBmdW5jdGlvbiAobWVzc2FnZSwgc3RhdHVzQ29kZSwgZGF0YSkge1xuICAgICAgICAgICAgLy8gbG9nb3V0IHRoZSB1c2VyIHNpbmNlIGl0J3MgaW4gYW4gaW52YWxpZCBzdGF0ZSB3aXRoIG5vIGdyb3VwIHNlbGVjdGVkXG4gICAgICAgICAgICBfdGhpcy5sb2dvdXQoKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgZXJyb3IgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGF0YSwgeyBzdGF0dXNUZXh0OiBtZXNzYWdlLCBzdGF0dXM6IHN0YXR1c0NvZGUgfSk7XG4gICAgICAgICAgICAgICAgJGQucmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBoYW5kbGVTdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgICAgICAgICAvL2pzY3M6ZGlzYWJsZVxuICAgICAgICAgICAgdG9rZW4gPSByZXNwb25zZS5hY2Nlc3NfdG9rZW47XG5cbiAgICAgICAgICAgIHZhciB1c2VySW5mbyA9IGRlY29kZVRva2VuKHRva2VuKTtcbiAgICAgICAgICAgIHZhciB1c2VyR3JvdXBPcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIGFkYXB0ZXJPcHRpb25zLCB7IHN1Y2Nlc3M6ICQubm9vcCwgdG9rZW46IHRva2VuIH0pO1xuICAgICAgICAgICAgX3RoaXMuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogdXNlckluZm8udXNlcl9pZCwgdG9rZW46IHRva2VuIH0sIHVzZXJHcm91cE9wdHMpLmRvbmUoIGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGEgPSB7YXV0aDogcmVzcG9uc2UsIHVzZXI6IHVzZXJJbmZvLCB1c2VyR3JvdXBzOiBtZW1iZXJJbmZvLCBncm91cFNlbGVjdGlvbjoge30gfTtcblxuICAgICAgICAgICAgICAgIHZhciBzZXNzaW9uSW5mbyA9IHtcbiAgICAgICAgICAgICAgICAgICAgJ2F1dGhfdG9rZW4nOiB0b2tlbixcbiAgICAgICAgICAgICAgICAgICAgJ2FjY291bnQnOiBhZGFwdGVyT3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgICAgICAncHJvamVjdCc6IGFkYXB0ZXJPcHRpb25zLnByb2plY3QsXG4gICAgICAgICAgICAgICAgICAgICd1c2VySWQnOiB1c2VySW5mby51c2VyX2lkXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAvLyBUaGUgZ3JvdXAgaXMgbm90IHJlcXVpcmVkIGlmIHRoZSB1c2VyIGlzIG5vdCBsb2dnaW5nIGludG8gYSBwcm9qZWN0XG4gICAgICAgICAgICAgICAgaWYgKCFhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHNhdmVTZXNzaW9uKHNlc3Npb25JbmZvKTtcbiAgICAgICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIGdyb3VwID0gbnVsbDtcbiAgICAgICAgICAgICAgICBpZiAobWVtYmVySW5mby5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgaGFuZGxlR3JvdXBFcnJvcignVGhlIHVzZXIgaGFzIG5vIGdyb3VwcyBhc3NvY2lhdGVkIGluIHRoaXMgYWNjb3VudCcsIDQwMSwgZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1lbWJlckluZm8ubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFNlbGVjdCB0aGUgb25seSBncm91cFxuICAgICAgICAgICAgICAgICAgICBncm91cCA9IG1lbWJlckluZm9bMF07XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZW1iZXJJbmZvLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGdyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBmaWx0ZXJlZEdyb3VwcyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAocmVzR3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzR3JvdXAuZ3JvdXBJZCA9PT0gZ3JvdXBJZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBmaWx0ZXJlZEdyb3Vwcy5sZW5ndGggPT09IDEgPyBmaWx0ZXJlZEdyb3Vwc1swXSA6IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGdyb3VwU2VsZWN0aW9uID0gZ3JvdXAuZ3JvdXBJZDtcbiAgICAgICAgICAgICAgICAgICAgZGF0YS5ncm91cFNlbGVjdGlvblthZGFwdGVyT3B0aW9ucy5wcm9qZWN0XSA9IGdyb3VwU2VsZWN0aW9uO1xuICAgICAgICAgICAgICAgICAgICB2YXIgc2Vzc2lvbkluZm9XaXRoR3JvdXAgPSAkLmV4dGVuZCh7fSwgc2Vzc2lvbkluZm8sIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICdncm91cElkJzogZ3JvdXAuZ3JvdXBJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICdncm91cE5hbWUnOiBncm91cC5uYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ2lzRmFjJzogX2ZpbmRVc2VySW5Hcm91cChncm91cC5tZW1iZXJzLCB1c2VySW5mby51c2VyX2lkKS5yb2xlID09PSAnZmFjaWxpdGF0b3InXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBzYXZlU2Vzc2lvbihzZXNzaW9uSW5mb1dpdGhHcm91cCk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBoYW5kbGVHcm91cEVycm9yKCdUaGlzIHVzZXIgaXMgYXNzb2NpYXRlZCB3aXRoIG1vcmUgdGhhbiBvbmUgZ3JvdXAuIFBsZWFzZSBzcGVjaWZ5IGEgZ3JvdXAgaWQgdG8gbG9nIGludG8gYW5kIHRyeSBhZ2FpbicsIDQwMywgZGF0YSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSkuZmFpbCgkZC5yZWplY3QpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBoYW5kbGVTdWNjZXNzO1xuICAgICAgICBhZGFwdGVyT3B0aW9ucy5lcnJvciA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgaWYgKGFkYXB0ZXJPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvLyBUcnkgdG8gbG9naW4gYXMgYSBzeXN0ZW0gdXNlclxuICAgICAgICAgICAgICAgIGFkYXB0ZXJPcHRpb25zLmFjY291bnQgPSBudWxsO1xuICAgICAgICAgICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBvdXRFcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICBfdGhpcy5hdXRoQWRhcHRlci5sb2dpbihhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRFcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgJGQucmVqZWN0KHJlc3BvbnNlKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgKiBMb2dzIHVzZXIgb3V0LlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dvdXQoKTtcbiAgICAqXG4gICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICpcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAqL1xuICAgIGxvZ291dDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyB0b2tlbjogdG9rZW4gfSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICB2YXIgcmVtb3ZlQ29va2llRm4gPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIHN0b3JlLnJlbW92ZShFUElfQ09PS0lFX0tFWSwgYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICAgICAgc3RvcmUucmVtb3ZlKEVQSV9TRVNTSU9OX0tFWSwgYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICAgICAgdG9rZW4gPSAnJztcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gdGhpcy5hdXRoQWRhcHRlci5sb2dvdXQoYWRhcHRlck9wdGlvbnMpLmRvbmUocmVtb3ZlQ29va2llRm4pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBleGlzdGluZyB1c2VyIGFjY2VzcyB0b2tlbiBpZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbi4gT3RoZXJ3aXNlLCBsb2dzIHRoZSB1c2VyIGluLCBjcmVhdGluZyBhIG5ldyB1c2VyIGFjY2VzcyB0b2tlbiwgYW5kIHJldHVybnMgdGhlIG5ldyB0b2tlbi4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgYXV0aE1nci5nZXRUb2tlbigpXG4gICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHRva2VuKSB7IFxuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZygnTXkgdG9rZW4gaXMgJywgdG9rZW4pOyBcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgaWYgKHRva2VuKSB7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKHRva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7IFxuICAgICAqICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7IGkgPCBncm91cHMubGVuZ3RoOyBpKyspIFxuICAgICAqICAgICAgICAgICAgICAgICAgeyBjb25zb2xlLmxvZyhncm91cHNbaV0ubmFtZSk7IH1cbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gZ2V0IGdyb3VwcyBmb3IgcGFydGljdWxhciB1c2VyXG4gICAgICogICAgICBhdXRoTWdyLmdldFVzZXJHcm91cHMoe3VzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHRva2VuOiBzYXZlZFByb2pBY2Nlc3NUb2tlbiB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBwYXJhbXNgIE9iamVjdCB3aXRoIGEgdXNlcklkIGFuZCB0b2tlbiBwcm9wZXJ0aWVzLlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIHVzZXJJZC4gSWYgbG9va2luZyB1cCBncm91cHMgZm9yIHRoZSBjdXJyZW50bHkgbG9nZ2VkIGluIHVzZXIsIHRoaXMgaXMgaW4gdGhlIHNlc3Npb24gaW5mb3JtYXRpb24uIE90aGVyd2lzZSwgcGFzcyBhIHN0cmluZy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy50b2tlbmAgVGhlIGF1dGhvcml6YXRpb24gY3JlZGVudGlhbHMgKGFjY2VzcyB0b2tlbikgdG8gdXNlIGZvciBjaGVja2luZyB0aGUgZ3JvdXBzIGZvciB0aGlzIHVzZXIuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBBIHRlYW0gbWVtYmVyJ3MgdG9rZW4gb3IgYSBwcm9qZWN0IGFjY2VzcyB0b2tlbiBjYW4gYWNjZXNzIGFsbCB0aGUgZ3JvdXBzIGZvciBhbGwgZW5kIHVzZXJzIGluIHRoZSB0ZWFtIG9yIHByb2plY3QuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFVzZXJHcm91cHM6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AgfSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgb3V0U3VjY2VzcyA9IGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3M7XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAvLyBUaGUgbWVtYmVyIEFQSSBpcyBhdCB0aGUgYWNjb3VudCBzY29wZSwgd2UgZmlsdGVyIGJ5IHByb2plY3RcbiAgICAgICAgICAgIGlmIChhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgbWVtYmVySW5mbyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdyb3VwLnByb2plY3QgPT09IGFkYXB0ZXJPcHRpb25zLnByb2plY3Q7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW21lbWJlckluZm9dKTtcbiAgICAgICAgICAgICRkLnJlc29sdmUobWVtYmVySW5mbyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIG1lbWJlckFkYXB0ZXIgPSBuZXcgTWVtYmVyQWRhcHRlcih7IHRva2VuOiBwYXJhbXMudG9rZW4gfSk7XG4gICAgICAgIG1lbWJlckFkYXB0ZXIuZ2V0R3JvdXBzRm9yVXNlcihwYXJhbXMsIGFkYXB0ZXJPcHRpb25zKS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgc2Vzc2lvbiBpbmZvcm1hdGlvbiBmb3IgdGhlIGN1cnJlbnQgdXNlciwgaW5jbHVkaW5nIHRoZSBgdXNlcklkYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGBncm91cElkYCwgYGdyb3VwTmFtZWAsIGBpc0ZhY2AgKHdoZXRoZXIgdGhlIGVuZCB1c2VyIGlzIGEgZmFjaWxpdGF0b3Igb2YgdGhpcyBncm91cCksIGFuZCBgYXV0aF90b2tlbmAgKHVzZXIgYWNjZXNzIHRva2VuKS5cbiAgICAgKlxuICAgICAqICpJbXBvcnRhbnQqOiBUaGlzIG1ldGhvZCBpcyBzeW5jaHJvbm91cy4gVGhlIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgcmV0dXJuZWQgaW1tZWRpYXRlbHkgaW4gYW4gb2JqZWN0OyBubyBjYWxsYmFja3Mgb3IgcHJvbWlzZXMgYXJlIG5lZWRlZC5cbiAgICAgKlxuICAgICAqIEJ5IGRlZmF1bHQsIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgc3RvcmVkIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLiBZb3UgY2FuIGNoYW5nZSB0aGlzIHdpdGggdGhlIGBzdG9yZWAgY29uZmlndXJhdGlvbiBvcHRpb24uIFxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm86IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiBnZXRTZXNzaW9uKG9wdGlvbnMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEF1dGhNYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2hhbm5lbCA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlJyk7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgYXJvdW5kIHRoZSBkZWZhdWx0IFtjb21ldGQgSmF2YVNjcmlwdCBsaWJyYXJ5XShodHRwOi8vZG9jcy5jb21ldGQub3JnLzIvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCksIGAkLmNvbWV0ZGAuIEl0IHByb3ZpZGVzIGEgZmV3IG5pY2UgZmVhdHVyZXMgdGhhdCBgJC5jb21ldGRgIGRvZXNuJ3QsIGluY2x1ZGluZzpcbiAqXG4gKiAqIEF1dG9tYXRpYyByZS1zdWJzY3JpcHRpb24gdG8gY2hhbm5lbHMgaWYgeW91IGxvc2UgeW91ciBjb25uZWN0aW9uXG4gKiAqIE9ubGluZSAvIE9mZmxpbmUgbm90aWZpY2F0aW9uc1xuICogKiAnRXZlbnRzJyBmb3IgY29tZXRkIG5vdGlmaWNhdGlvbnMgKGluc3RlYWQgb2YgaGF2aW5nIHRvIGxpc3RlbiBvbiBzcGVjaWZpYyBtZXRhIGNoYW5uZWxzKVxuICpcbiAqIFdoaWxlIHlvdSBjYW4gd29yayBkaXJlY3RseSB3aXRoIHRoZSBDaGFubmVsIE1hbmFnZXIgdGhyb3VnaCBOb2RlLmpzIChmb3IgZXhhbXBsZSwgYHJlcXVpcmUoJ21hbmFnZXIvY2hhbm5lbC1tYW5hZ2VyJylgKSAtLSBvciBldmVuIHdvcmsgZGlyZWN0bHkgd2l0aCBgJC5jb21ldGRgIGFuZCBFcGljZW50ZXIncyB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIC0tIG1vc3Qgb2Z0ZW4gaXQgd2lsbCBiZSBlYXNpZXN0IHRvIHdvcmsgd2l0aCB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKS4gVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIHRoYXQgaW5zdGFudGlhdGVzIGEgQ2hhbm5lbCBNYW5hZ2VyIHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgTWFuYWdlci4gKFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLilcbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgTWFuYWdlciBpbiBjbGllbnQtc2lkZSBKYXZhU2NyaXB0LCBpbnN0YW50aWF0ZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSwgZ2V0IHRoZSBjaGFubmVsLCB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gKlxuICogICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAqICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgTWFuYWdlci4gQmVzaWRlcyB0aGUgY29tbW9uIG9wdGlvbnMgbGlzdGVkIGhlcmUsIHNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIG90aGVyIHN1cHBvcnRlZCBvcHRpb25zLlxuICogKiBgb3B0aW9ucy51cmxgIFRoZSBDb21ldGQgZW5kcG9pbnQgVVJMLlxuICogKiBgb3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkYCBXaGV0aGVyIHdlYnNvY2tldCBzdXBwb3J0IGlzIGFjdGl2ZSAoYm9vbGVhbikuXG4gKiAqIGBvcHRpb25zLmNoYW5uZWxgIE90aGVyIGRlZmF1bHRzIHRvIHBhc3Mgb24gdG8gaW5zdGFuY2VzIG9mIHRoZSB1bmRlcmx5aW5nIENoYW5uZWwgU2VydmljZS4gU2VlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pIGZvciBkZXRhaWxzLlxuICpcbiAqL1xudmFyIENoYW5uZWxNYW5hZ2VyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICBpZiAoISQuY29tZXRkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tZXRkIGxpYnJhcnkgbm90IGZvdW5kLiBQbGVhc2UgaW5jbHVkZSBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy51cmwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhbiB1cmwgZm9yIHRoZSBjb21ldGQgc2VydmVyJyk7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbG9nIGxldmVsIGZvciB0aGUgY2hhbm5lbCAobG9ncyB0byBjb25zb2xlKS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGxvZ0xldmVsOiAnaW5mbycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlLiBEZWZhdWx0cyB0byBgZmFsc2VgOyBFcGljZW50ZXIgZG9lc24ndCBjdXJyZW50bHkgc3VwcG9ydCBjb21tdW5pY2F0aW9uIHRocm91Z2ggd2Vic29ja2V0cy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICB3ZWJzb2NrZXRFbmFibGVkOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogSWYgZmFsc2UgZWFjaCBpbnN0YW5jZSBvZiBDaGFubmVsIHdpbGwgaGF2ZSBhIHNlcGFyYXRlIGNvbWV0ZCBjb25uZWN0aW9uIHRvIHNlcnZlciwgd2hpY2ggY291bGQgYmUgbm9pc3kuIFNldCB0byB0cnVlIHRvIHJlLXVzZSB0aGUgc2FtZSBjb25uZWN0aW9uIGFjcm9zcyBpbnN0YW5jZXMuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2hhcmVDb25uZWN0aW9uOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLyksIHdoaWNoIGFyZSBjcmVhdGVkIHRocm91Z2ggYGdldENoYW5uZWwoKWAuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBjaGFubmVsOiB7XG5cbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMgPSBbXTtcbiAgICB0aGlzLm9wdGlvbnMgPSBkZWZhdWx0Q29tZXRPcHRpb25zO1xuXG4gICAgaWYgKGRlZmF1bHRDb21ldE9wdGlvbnMuc2hhcmVDb25uZWN0aW9uICYmIENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkKSB7XG4gICAgICAgIHRoaXMuY29tZXRkID0gQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQ7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICB2YXIgY29tZXRkID0gbmV3ICQuQ29tZXRkKCk7XG4gICAgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQgPSBjb21ldGQ7XG5cbiAgICBjb21ldGQud2Vic29ja2V0RW5hYmxlZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMud2Vic29ja2V0RW5hYmxlZDtcblxuICAgIHRoaXMuaXNDb25uZWN0ZWQgPSBmYWxzZTtcbiAgICB2YXIgY29ubmVjdGlvbkJyb2tlbiA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignZGlzY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIGNvbm5lY3Rpb25TdWNjZWVkZWQgPSBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIoJ2Nvbm5lY3QnLCBtZXNzYWdlKTtcbiAgICB9O1xuICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICBjb21ldGQuY29uZmlndXJlKGRlZmF1bHRDb21ldE9wdGlvbnMpO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9jb25uZWN0JywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgdmFyIHdhc0Nvbm5lY3RlZCA9IHRoaXMuaXNDb25uZWN0ZWQ7XG4gICAgICAgIHRoaXMuaXNDb25uZWN0ZWQgPSAobWVzc2FnZS5zdWNjZXNzZnVsID09PSB0cnVlKTtcbiAgICAgICAgaWYgKCF3YXNDb25uZWN0ZWQgJiYgdGhpcy5pc0Nvbm5lY3RlZCkgeyAvL0Nvbm5lY3RpbmcgZm9yIHRoZSBmaXJzdCB0aW1lXG4gICAgICAgICAgICBjb25uZWN0aW9uU3VjY2VlZGVkLmNhbGwodGhpcywgbWVzc2FnZSk7XG4gICAgICAgIH0gZWxzZSBpZiAod2FzQ29ubmVjdGVkICYmICF0aGlzLmlzQ29ubmVjdGVkKSB7IC8vT25seSB0aHJvdyBkaXNjb25uZWN0ZWQgbWVzc2FnZSBmcm8gdGhlIGZpcnN0IGRpc2Nvbm5lY3QsIG5vdCBvbmNlIHBlciB0cnlcbiAgICAgICAgICAgIGNvbm5lY3Rpb25Ccm9rZW4uY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH0uYmluZCh0aGlzKSk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Rpc2Nvbm5lY3QnLCBjb25uZWN0aW9uQnJva2VuKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvaGFuZHNoYWtlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgaWYgKG1lc3NhZ2Uuc3VjY2Vzc2Z1bCkge1xuICAgICAgICAgICAgLy9odHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0X3N1YnNjcmliZS5odG1sI2phdmFzY3JpcHRfc3Vic2NyaWJlX21ldGFfY2hhbm5lbHNcbiAgICAgICAgICAgIC8vIF4gXCJkeW5hbWljIHN1YnNjcmlwdGlvbnMgYXJlIGNsZWFyZWQgKGxpa2UgYW55IG90aGVyIHN1YnNjcmlwdGlvbikgYW5kIHRoZSBhcHBsaWNhdGlvbiBuZWVkcyB0byBmaWd1cmUgb3V0IHdoaWNoIGR5bmFtaWMgc3Vic2NyaXB0aW9uIG11c3QgYmUgcGVyZm9ybWVkIGFnYWluXCJcbiAgICAgICAgICAgIGNvbWV0ZC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgJChtZS5jdXJyZW50U3Vic2NyaXB0aW9ucykuZWFjaChmdW5jdGlvbiAoaW5kZXgsIHN1YnMpIHtcbiAgICAgICAgICAgICAgICAgICAgY29tZXRkLnJlc3Vic2NyaWJlKHN1YnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vT3RoZXIgaW50ZXJlc3RpbmcgZXZlbnRzIGZvciByZWZlcmVuY2VcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3N1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3N1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWJzY3JpYmUnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCd1bnN1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvcHVibGlzaCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3B1Ymxpc2gnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3Vuc3VjY2Vzc2Z1bCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ2Vycm9yJywgbWVzc2FnZSk7XG4gICAgfSk7XG5cbiAgICBjb21ldGQuaGFuZHNoYWtlKCk7XG5cbiAgICB0aGlzLmNvbWV0ZCA9IGNvbWV0ZDtcbn07XG5cblxuQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgIHZhciBjaGFubmVsID0gY20uZ2V0Q2hhbm5lbCgpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvL0lmIHlvdSBqdXN0IHdhbnQgdG8gcGFzcyBpbiBhIHN0cmluZ1xuICAgICAgICBpZiAob3B0aW9ucyAmJiAhJC5pc1BsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAgICAgdHJhbnNwb3J0OiB0aGlzLmNvbWV0ZFxuICAgICAgICB9O1xuICAgICAgICB2YXIgY2hhbm5lbCA9IG5ldyBDaGFubmVsKCQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLm9wdGlvbnMuY2hhbm5lbCwgZGVmYXVsdHMsIG9wdGlvbnMpKTtcblxuXG4gICAgICAgIC8vV3JhcCBzdWJzIGFuZCB1bnN1YnMgc28gd2UgY2FuIHVzZSBpdCB0byByZS1hdHRhY2ggaGFuZGxlcnMgYWZ0ZXIgYmVpbmcgZGlzY29ubmVjdGVkXG4gICAgICAgIHZhciBzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHN1YmlkID0gc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyAgPSB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmNvbmNhdChzdWJpZCk7XG4gICAgICAgICAgICByZXR1cm4gc3ViaWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuXG4gICAgICAgIHZhciB1bnN1YnMgPSBjaGFubmVsLnVuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnVuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJlbW92ZWQgPSB1bnN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zW2ldLmlkID09PSByZW1vdmVkLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZW1vdmVkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlclxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIChtb3JlIGdlbmVyaWMpIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pLCB0byBpbnN0YW50aWF0ZSBpdCB3aXRoIEVwaWNlbnRlci1zcGVjaWZpYyBkZWZhdWx0cy4gSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGluY2x1ZGluZyBhIG5vdGlmaWNhdGlvbiBvciBjaGF0IGZlYXR1cmUgaW4geW91ciBwcm9qZWN0LCB1c2luZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIHByb2JhYmx5IHRoZSBlYXNpZXN0IHdheSB0byBnZXQgc3RhcnRlZC5cbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXI6IGluc3RhbnRpYXRlIGl0LCBnZXQgdGhlIGNoYW5uZWwgb2YgdGhlIHNjb3BlIHlvdSB3YW50IChbdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLCBvciBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpKSwgdGhlbiB1c2UgdGhlIGNoYW5uZWwncyBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIHN1YnNjcmliZSB0byB0b3BpY3Mgb3IgcHVibGlzaCBkYXRhIHRvIHRvcGljcy5cbiAqXG4gKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAqXG4gKiBGb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIEVwaWNlbnRlcidzIHB1c2ggY2hhbm5lbCwgc2VlIHRoZSBpbnRyb2R1Y3Rvcnkgbm90ZXMgb24gdGhlIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIHBhZ2UuXG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYHNlcnZlcmAgT2JqZWN0IHdpdGggZGV0YWlscyBhYm91dCB0aGUgRXBpY2VudGVyIHByb2plY3QgZm9yIHRoaXMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbnN0YW5jZS5cbiAqICogYHNlcnZlci5hY2NvdW50YCBUaGUgRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgc2VydmVyLnByb2plY3RgIEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICovXG5cbnZhciBDaGFubmVsTWFuYWdlciA9IHJlcXVpcmUoJy4vY2hhbm5lbC1tYW5hZ2VyJyk7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgdXJsU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlJyk7XG5cbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBzZXNzaW9uID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG52YXIgZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvciA9IGZ1bmN0aW9uICh2YWx1ZSwgc2Vzc2lvbktleU5hbWUsIHNldHRpbmdzKSB7XG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgaWYgKHNldHRpbmdzICYmIHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXSkge1xuICAgICAgICAgICAgdmFsdWUgPSBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV07XG4gICAgICAgIH0gZWxzZSBpZiAodXNlckluZm9bc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHVzZXJJbmZvW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihzZXNzaW9uS2V5TmFtZSArICcgbm90IGZvdW5kLiBQbGVhc2UgbG9nLWluIGFnYWluLCBvciBzcGVjaWZ5ICcgKyBzZXNzaW9uS2V5TmFtZSArICcgZXhwbGljaXRseScpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbn07XG52YXIgX19zdXBlciA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZTtcbnZhciBFcGljZW50ZXJDaGFubmVsTWFuYWdlciA9IGNsYXNzRnJvbShDaGFubmVsTWFuYWdlciwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcblxuICAgICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgICAgICBhY2NvdW50OiB1c2VySW5mby5hY2NvdW50LFxuICAgICAgICAgICAgcHJvamVjdDogdXNlckluZm8ucHJvamVjdCxcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIHVzZXJJbmZvLCBvcHRpb25zKTtcblxuICAgICAgICB2YXIgdXJsT3B0cyA9IHVybFNlcnZpY2UoZGVmYXVsdENvbWV0T3B0aW9ucy5zZXJ2ZXIpO1xuICAgICAgICBpZiAoIWRlZmF1bHRDb21ldE9wdGlvbnMudXJsKSB7XG4gICAgICAgICAgICAvL0RlZmF1bHQgZXBpY2VudGVyIGNvbWV0ZCBlbmRwb2ludFxuICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy51cmwgPSB1cmxPcHRzLnByb3RvY29sICsgJzovLycgKyB1cmxPcHRzLmhvc3QgKyAnL2NoYW5uZWwvc3Vic2NyaWJlJztcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgZGVmYXVsdENvbWV0T3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBnaXZlbiBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLiBUaGUgZ3JvdXAgbXVzdCBleGlzdCBpbiB0aGUgYWNjb3VudCAodGVhbSkgYW5kIHByb2plY3QgcHJvdmlkZWQuXG4gICAgICpcbiAgICAgKiBUaGVyZSBhcmUgbm8gbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWw7IGFsbCBtZXNzYWdlcyBhcmUgdXNlci1vcmlnaW5hdGVkLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJ2Jyb2FkY2FzdHMnLCBjYWxsYmFjayk7XG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBHcm91cCB0byBicm9hZGNhc3QgdG8uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldEdyb3VwQ2hhbm5lbDogZnVuY3Rpb24gKGdyb3VwTmFtZSkge1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScpO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2dyb3VwJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lXS5qb2luKCcvJyk7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICogICAgICAgICBydW46IHsgbW9kZWw6ICdtb2RlbC5lcW4nIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICogICAgIHdvcmxkTWFuYWdlci5nZXRDdXJyZW50V29ybGQoKS50aGVuKGZ1bmN0aW9uICh3b3JsZE9iamVjdCwgd29ybGRBZGFwdGVyKSB7XG4gICAgICogICAgICAgICB2YXIgd29ybGRDaGFubmVsID0gY20uZ2V0V29ybGRDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHdvcmxkQ2hhbm5lbC5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICogICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICogICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFRoZSB3b3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFdvcmxkQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCBncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHdvcmxkaWQgPSAoJC5pc1BsYWluT2JqZWN0KHdvcmxkKSAmJiB3b3JsZC5pZCkgPyB3b3JsZC5pZCA6IHdvcmxkO1xuICAgICAgICBpZiAoIXdvcmxkaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgYSB3b3JsZCBpZCcpO1xuICAgICAgICB9XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJyk7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvd29ybGQnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgY3VycmVudCBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaW4gdGhhdCB1c2VyJ3MgY3VycmVudCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS4gTm90ZSB0aGF0IHRoaXMgY2hhbm5lbCBvbmx5IGdldHMgbm90aWZpY2F0aW9ucyBmb3Igd29ybGRzIGN1cnJlbnRseSBpbiBtZW1vcnkuIChTZWUgbW9yZSBiYWNrZ3JvdW5kIG9uIFtwZXJzaXN0ZW5jZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlKS4pXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB1c2VyQ2hhbm5lbCA9IGNtLmdldFVzZXJDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHVzZXJDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFVzZXJDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXIsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVzZXJpZCA9ICgkLmlzUGxhaW5PYmplY3QodXNlcikgJiYgdXNlci5pZCkgPyB1c2VyLmlkIDogdXNlcjtcbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkLCB1c2VyaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIHRoYXQgYXV0b21hdGljYWxseSB0cmFja3MgdGhlIHByZXNlbmNlIG9mIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhhdCBpcywgd2hldGhlciB0aGUgZW5kIHVzZXIgaXMgY3VycmVudGx5IG9ubGluZSBpbiB0aGlzIGdyb3VwIGFuZCB3b3JsZC4gTm90aWZpY2F0aW9ucyBhcmUgYXV0b21hdGljYWxseSBzZW50IHdoZW4gdGhlIGVuZCB1c2VyIGNvbWVzIG9ubGluZSwgYW5kIHdoZW4gdGhlIGVuZCB1c2VyIGdvZXMgb2ZmbGluZSAobm90IHByZXNlbnQgZm9yIG1vcmUgdGhhbiAyIG1pbnV0ZXMpLiBVc2VmdWwgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZm9yIGxldHRpbmcgZWFjaCBlbmQgdXNlciBrbm93IHdoZXRoZXIgb3RoZXIgdXNlcnMgaW4gdGhlaXIgc2hhcmVkIHdvcmxkIGFyZSBhbHNvIG9ubGluZS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIG1vZGVsOiAnbW9kZWwuZXFuJ1xuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZFNlcnZpY2UpIHtcbiAgICAgKiAgICAgICAgIHZhciBwcmVzZW5jZUNoYW5uZWwgPSBjbS5nZXRQcmVzZW5jZUNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgcHJlc2VuY2VDaGFubmVsLm9uKCdwcmVzZW5jZScsIGZ1bmN0aW9uIChldnQsIG5vdGlmaWNhdGlvbikge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZyhub3RpZmljYXRpb24ub25saW5lLCBub3RpZmljYXRpb24udXNlcklkKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB3b3JsZGAgV29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB1c2VyaWRgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFByZXNlbmNlQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCB1c2VyaWQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgdmFyIGxhc3RQaW5nVGltZSA9IHsgfTtcblxuICAgICAgICB2YXIgUElOR19JTlRFUlZBTCA9IDYwMDA7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCdpbnRlcm5hbC1waW5nLWNoYW5uZWwnLCBmdW5jdGlvbiAobm90aWZpY2F0aW9uKSB7XG4gICAgICAgICAgICB2YXIgaW5jb21pbmdVc2VySWQgPSBub3RpZmljYXRpb24uZGF0YS51c2VyO1xuICAgICAgICAgICAgaWYgKCFsYXN0UGluZ1RpbWVbaW5jb21pbmdVc2VySWRdICYmIGluY29taW5nVXNlcklkICE9PSB1c2VyaWQpIHtcbiAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDogaW5jb21pbmdVc2VySWQsIG9ubGluZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIHsgdXNlcjogdXNlcmlkIH0pO1xuXG4gICAgICAgICAgICAkLmVhY2gobGFzdFBpbmdUaW1lLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBub3cgPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSAmJiB2YWx1ZSArIChQSU5HX0lOVEVSVkFMICogMikgPCBub3cpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2tleV0gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDoga2V5LCBvbmxpbmU6IGZhbHNlIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBQSU5HX0lOVEVSVkFMKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIGNvbGxlY3Rpb24uIChUaGUgY29sbGVjdGlvbiBuYW1lIGlzIHNwZWNpZmllZCBpbiB0aGUgYHJvb3RgIGFyZ3VtZW50IHdoZW4gdGhlIFtEYXRhIFNlcnZpY2VdKC4uL2RhdGEtYXBpLXNlcnZpY2UvKSBpcyBpbnN0YW50aWF0ZWQuKSBNdXN0IGJlIG9uZSBvZiB0aGUgY29sbGVjdGlvbnMgaW4gdGhpcyBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBhdXRvbWF0aWMgbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWwgd2hlbiBkYXRhIGlzIGNyZWF0ZWQsIHVwZGF0ZWQsIG9yIGRlbGV0ZWQgaW4gdGhpcyBjb2xsZWN0aW9uLiBTZWUgbW9yZSBvbiBbYXV0b21hdGljIG1lc3NhZ2VzIHRvIHRoZSBkYXRhIGNoYW5uZWxdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNkYXRhLW1lc3NhZ2VzKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZ2MgPSBjbS5nZXREYXRhQ2hhbm5lbCgnc3VydmV5LXJlc3BvbnNlcycpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEsIG1ldGEpIHtcbiAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIG1ldGEuZGF0ZSBpcyB0aW1lIG9mIGNoYW5nZSxcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnN1YlR5cGUgaXMgdGhlIGtpbmQgb2YgY2hhbmdlOiBuZXcsIHVwZGF0ZSwgb3IgZGVsZXRlXG4gICAgICogICAgICAgICAgLy8gbWV0YS5wYXRoIGlzIHRoZSBmdWxsIHBhdGggdG8gdGhlIGNoYW5nZWQgZGF0YVxuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKG1ldGEpO1xuICAgICAqICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgY29sbGVjdGlvbmAgTmFtZSBvZiBjb2xsZWN0aW9uIHdob3NlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIHlvdSB3YW50IHRvIHJlY2VpdmUuXG4gICAgICovXG4gICAgZ2V0RGF0YUNoYW5uZWw6IGZ1bmN0aW9uIChjb2xsZWN0aW9uKSB7XG4gICAgICAgIGlmICghY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIGNvbGxlY3Rpb24gdG8gbGlzdGVuIG9uLicpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2RhdGEnLCBhY2NvdW50LCBwcm9qZWN0LCBjb2xsZWN0aW9uXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgLy9UT0RPOiBGaXggYWZ0ZXIgRXBpY2VudGVyIGJ1ZyBpcyByZXNvbHZlZFxuICAgICAgICB2YXIgb2xkc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjYWxsYmFja1dpdGhDbGVhbkRhdGEgPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgICAgICAgICAgICAgIHZhciBtZXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYXlsb2FkLmNoYW5uZWwsXG4gICAgICAgICAgICAgICAgICAgIHN1YlR5cGU6IHBheWxvYWQuZGF0YS5zdWJUeXBlLFxuICAgICAgICAgICAgICAgICAgICBkYXRlOiBwYXlsb2FkLmRhdGEuZGF0ZVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGFjdHVhbERhdGEgPSBwYXlsb2FkLmRhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICBpZiAoYWN0dWFsRGF0YS5kYXRhKSB7IC8vRGVsZXRlIG5vdGlmaWNhdGlvbnMgYXJlIG9uZSBkYXRhLWxldmVsIGJlaGluZCBvZiBjb3Vyc2VcbiAgICAgICAgICAgICAgICAgICAgYWN0dWFsRGF0YSA9IGFjdHVhbERhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIGFjdHVhbERhdGEsIG1ldGEpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aENsZWFuRGF0YSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVQSV9DT09LSUVfS0VZOiAnZXBpY2VudGVyLnByb2plY3QudG9rZW4nLFxuICAgIEVQSV9TRVNTSU9OX0tFWTogJ2VwaWNlbnRlci51c2VyLnNlc3Npb24nLFxuICAgIFNUUkFURUdZX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLXNjZW5hcmlvJ1xufTsiLCIvKipcbiogIyMgUnVuIE1hbmFnZXJcbipcbiogVGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBhY2Nlc3MgdG8gcnVucyBmb3IgeW91ciBwcm9qZWN0LiBUaGlzIGFsbG93cyB5b3UgdG8gcmVhZCBhbmQgdXBkYXRlIHZhcmlhYmxlcywgY2FsbCBvcGVyYXRpb25zLCBldGMuIEFkZGl0aW9uYWxseSwgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLiBTcGVjaWZpY2FsbHksIHlvdSBjYW4gc2VsZWN0IFtydW4gY3JlYXRpb24gc3RyYXRlZ2llcyAocnVsZXMpXSguLi8uLi9zdHJhdGVneS8pIGZvciB3aGljaCBydW5zIGVuZCB1c2VycyBvZiB5b3VyIHByb2plY3Qgd29yayB3aXRoIHdoZW4gdGhleSBsb2cgaW4gdG8geW91ciBwcm9qZWN0LlxuKlxuKiBUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGNyZWF0ZSBuZXcgcnVucywgaW5jbHVkaW5nIHRoZSBFcGljZW50ZXIuanMgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSwgdGhlIFJFU0ZUZnVsIFtSdW4gQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkpIGFuZCB0aGUgW01vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLykuIEhvd2V2ZXIsIGZvciBzb21lIHByb2plY3RzIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gcGljayB1cCB3aGVyZSB0aGUgdXNlciBsZWZ0IG9mZiwgdXNpbmcgYW4gZXhpc3RpbmcgcnVuLiBBbmQgaW4gc29tZSBwcm9qZWN0cywgd2hldGhlciB0byBjcmVhdGUgYSBuZXcgcnVuIG9yIHVzZSBhbiBleGlzdGluZyBvbmUgaXMgY29uZGl0aW9uYWwsIGZvciBleGFtcGxlIGJhc2VkIG9uIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZXhpc3RpbmcgcnVuIG9yIHlvdXIgb3duIGtub3dsZWRnZSBhYm91dCB0aGUgbW9kZWwuIFRoZSBSdW4gTWFuYWdlciBwcm92aWRlcyB0aGlzIGxldmVsIG9mIGNvbnRyb2w6IHlvdXIgY2FsbCB0byBgZ2V0UnVuKClgLCByYXRoZXIgdGhhbiBhbHdheXMgcmV0dXJuaW5nIGEgbmV3IHJ1biwgcmV0dXJucyBhIHJ1biBiYXNlZCBvbiB0aGUgc3RyYXRlZ3kgeW91J3ZlIHNwZWNpZmllZC4gKE5vdGUgdGhhdCBtYW55IG9mIHRoZSBFcGljZW50ZXIgc2FtcGxlIHByb2plY3RzIHVzZSBhIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LCBiZWNhdXNlIGdlbmVyYWxseSB0aGUgc2FtcGxlIHByb2plY3RzIGFyZSBwbGF5ZWQgaW4gb25lIGVuZCB1c2VyIHNlc3Npb24gYW5kIGRvbid0IGNhcmUgYWJvdXQgcnVuIHN0YXRlcyBvciBydW4gc3RyYXRlZ2llcy4pXG4qXG4qXG4qICMjIyBVc2luZyB0aGUgUnVuIE1hbmFnZXIgdG8gY3JlYXRlIGFuZCBhY2Nlc3MgcnVuc1xuKlxuKiBUbyB1c2UgdGhlIFJ1biBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuKlxuKiAgICogYHJ1bmA6IChyZXF1aXJlZCkgUnVuIG9iamVjdC4gTXVzdCBjb250YWluOlxuKiAgICAgICAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICAgICAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4qICAgICAgICogYG1vZGVsYDogVGhlIG5hbWUgb2YgeW91ciBwcmltYXJ5IG1vZGVsIGZpbGUuIChTZWUgbW9yZSBvbiBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4pXG4qICAgICAgICogYHNjb3BlYDogKG9wdGlvbmFsKSBTY29wZSBvYmplY3QgZm9yIHRoZSBydW4sIGZvciBleGFtcGxlIGBzY29wZS5ncm91cGAgd2l0aCB2YWx1ZSBvZiB0aGUgbmFtZSBvZiB0aGUgZ3JvdXAuXG4qICAgICAgICogYHNlcnZlcmA6IChvcHRpb25hbCkgQW4gb2JqZWN0IHdpdGggb25lIGZpZWxkLCBgaG9zdGAuIFRoZSB2YWx1ZSBvZiBgaG9zdGAgaXMgdGhlIHN0cmluZyBgYXBpLmZvcmlvLmNvbWAsIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4qICAgICAgICogYGZpbGVzYDogKG9wdGlvbmFsKSBJZiBhbmQgb25seSBpZiB5b3UgYXJlIHVzaW5nIGEgVmVuc2ltIG1vZGVsIGFuZCB5b3UgaGF2ZSBhZGRpdGlvbmFsIGRhdGEgdG8gcGFzcyBpbiB0byB5b3VyIG1vZGVsLCB5b3UgY2FuIHBhc3MgYSBgZmlsZXNgIG9iamVjdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgZmlsZXMsIGZvciBleGFtcGxlOiBgXCJmaWxlc1wiOiB7XCJkYXRhXCI6IFwibXlFeHRyYURhdGEueGxzXCJ9YC4gKE5vdGUgdGhhdCB5b3UnbGwgYWxzbyBuZWVkIHRvIGFkZCB0aGlzIHNhbWUgZmlsZXMgb2JqZWN0IHRvIHlvdXIgVmVuc2ltIFtjb25maWd1cmF0aW9uIGZpbGVdKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltLykuKSBTZWUgdGhlIFt1bmRlcmx5aW5nIE1vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLyNwb3N0LWNyZWF0aW5nLWEtbmV3LXJ1bi1mb3ItdGhpcy1wcm9qZWN0KSBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbi5cbipcbiogICAqIGBzdHJhdGVneWA6IChvcHRpb25hbCkgUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4qXG4qICAgKiBgc2Vzc2lvbktleWA6IChvcHRpb25hbCkgTmFtZSBvZiBicm93c2VyIGNvb2tpZSBpbiB3aGljaCB0byBzdG9yZSBydW4gaW5mb3JtYXRpb24sIGluY2x1ZGluZyBydW4gaWQuIE1hbnkgY29uZGl0aW9uYWwgc3RyYXRlZ2llcywgaW5jbHVkaW5nIHRoZSBwcm92aWRlZCBzdHJhdGVnaWVzLCByZWx5IG9uIHRoaXMgYnJvd3NlciBjb29raWUgdG8gc3RvcmUgdGhlIHJ1biBpZCBhbmQgaGVscCBtYWtlIHRoZSBkZWNpc2lvbiBvZiB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZS4gVGhlIG5hbWUgb2YgdGhpcyBjb29raWUgZGVmYXVsdHMgdG8gYGVwaWNlbnRlci1zY2VuYXJpb2AgYW5kIGNhbiBiZSBzZXQgd2l0aCB0aGUgYHNlc3Npb25LZXlgIHBhcmFtZXRlci5cbipcbipcbiogQWZ0ZXIgaW5zdGFudGlhdGluZyBhIFJ1biBNYW5hZ2VyLCBtYWtlIGEgY2FsbCB0byBgZ2V0UnVuKClgIHdoZW5ldmVyIHlvdSBuZWVkIHRvIGFjY2VzcyBhIHJ1biBmb3IgdGhpcyBlbmQgdXNlci4gVGhlIGBSdW5NYW5hZ2VyLnJ1bmAgY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLiBUaGUgUnVuIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBhY2Nlc3MgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy5cbipcbiogKipFeGFtcGxlKipcbipcbiogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiogICAgICAgICAgIHJ1bjoge1xuKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJyxcbiogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiogICAgICAgICAgIH0sXG4qICAgICAgICAgICBzdHJhdGVneTogJ2Fsd2F5cy1uZXcnLFxuKiAgICAgICAgICAgc2Vzc2lvbktleTogJ2VwaWNlbnRlci1zZXNzaW9uJ1xuKiAgICAgICB9KTtcbiogICAgICAgcm0uZ2V0UnVuKClcbiogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuKiAgICAgICAgICAgICAgIC8vIHRoZSByZXR1cm4gdmFsdWUgb2YgZ2V0UnVuKCkgaXMgYSBydW4gb2JqZWN0XG4qICAgICAgICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gYWxzbyBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuKiAgICAgICAgICAgICAgIC8vIHNvIGFueSBSdW4gU2VydmljZSBtZXRob2QgaXMgdmFsaWQgaGVyZVxuKiAgICAgICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiogICAgICAgfSlcbipcbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBzdHJhdGVnaWVzTWFwID0gcmVxdWlyZSgnLi9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcCcpO1xudmFyIHNwZWNpYWxPcGVyYXRpb25zID0gcmVxdWlyZSgnLi9zcGVjaWFsLW9wZXJhdGlvbnMnKTtcbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcblxuXG5mdW5jdGlvbiBwYXRjaFJ1blNlcnZpY2Uoc2VydmljZSwgbWFuYWdlcikge1xuICAgIGlmIChzZXJ2aWNlLnBhdGNoZWQpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuXG4gICAgdmFyIG9yaWcgPSBzZXJ2aWNlLmRvO1xuICAgIHNlcnZpY2UuZG8gPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHJlc2VydmVkT3BzID0gT2JqZWN0LmtleXMoc3BlY2lhbE9wZXJhdGlvbnMpO1xuICAgICAgICBpZiAocmVzZXJ2ZWRPcHMuaW5kZXhPZihvcGVyYXRpb24pID09PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG9yaWcuYXBwbHkoc2VydmljZSwgYXJndW1lbnRzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT3BlcmF0aW9uc1tvcGVyYXRpb25dLmNhbGwoc2VydmljZSwgcGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBzZXJ2aWNlLnBhdGNoZWQgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHNlcnZpY2U7XG59XG5cblxuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cblxuICAgIHN0cmF0ZWd5OiAnbmV3LWlmLWluaXRpYWxpemVkJ1xufTtcblxuZnVuY3Rpb24gUnVuTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMucnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICB0aGlzLnJ1biA9IHRoaXMub3B0aW9ucy5ydW47XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5ydW4gPSBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMucnVuKTtcbiAgICB9XG5cbiAgICBwYXRjaFJ1blNlcnZpY2UodGhpcy5ydW4sIHRoaXMpO1xuXG4gICAgdmFyIFN0cmF0ZWd5Q3RvciA9IHR5cGVvZiB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgPT09ICdmdW5jdGlvbicgPyB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgOiBzdHJhdGVnaWVzTWFwW3RoaXMub3B0aW9ucy5zdHJhdGVneV07XG5cbiAgICBpZiAoIVN0cmF0ZWd5Q3Rvcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NwZWNpZmllZCBydW4gY3JlYXRpb24gc3RyYXRlZ3kgd2FzIGludmFsaWQ6JywgdGhpcy5vcHRpb25zLnN0cmF0ZWd5KTtcbiAgICB9XG5cbiAgICB0aGlzLnN0cmF0ZWd5ID0gbmV3IFN0cmF0ZWd5Q3Rvcih0aGlzLnJ1biwgdGhpcy5vcHRpb25zKTtcbn1cblxuUnVuTWFuYWdlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSAnZ29vZCcgcnVuLlxuICAgICAqXG4gICAgICogQSBnb29kIHJ1biBpcyBkZWZpbmVkIGJ5IHRoZSBzdHJhdGVneS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBzdHJhdGVneSBpcyBgYWx3YXlzLW5ld2AsIHRoZSBjYWxsXG4gICAgICogdG8gYGdldFJ1bigpYCBhbHdheXMgcmV0dXJucyBhIG5ld2x5IGNyZWF0ZWQgcnVuOyBpZiB0aGUgc3RyYXRlZ3kgaXMgYG5ldy1pZi1wZXJzaXN0ZWRgLFxuICAgICAqIGBnZXRSdW4oKWAgY3JlYXRlcyBhIG5ldyBydW4gaWYgdGhlIHByZXZpb3VzIHJ1biBpcyBpbiBhIHBlcnNpc3RlZCBzdGF0ZSwgb3RoZXJ3aXNlXG4gICAgICogaXQgcmV0dXJucyB0aGUgcHJldmlvdXMgcnVuLiBTZWUgW1J1biBNYW5hZ2VyIFN0cmF0ZWdpZXNdKC4uLy4uL3N0cmF0ZWd5LykgZm9yIG1vcmUgb24gc3RyYXRlZ2llcy5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5nZXRSdW4oKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqIEByZXR1cm4geyRwcm9taXNlfSBQcm9taXNlIHRvIGNvbXBsZXRlIHRoZSBjYWxsLlxuICAgICAqL1xuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdHJhdGVneVxuICAgICAgICAgICAgICAgIC5nZXRSdW4oKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSBuZXcgcnVuLCByZWdhcmRsZXNzIG9mIHN0cmF0ZWd5OiBmb3JjZSBjcmVhdGlvbiBvZiBhIG5ldyBydW4uXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgcm0ucmVzZXQoKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIChuZXcpIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBydW5TZXJ2aWNlT3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgUnVuIFNlcnZpY2UuIFNlZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBmb3IgbW9yZS5cbiAgICAgKi9cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5LnJlc2V0KHJ1blNlcnZpY2VPcHRpb25zKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJ1bk1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIC8vIGFsd2F5cyBjcmVhdGUgYSBuZXcgcnVuIVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1ha2VTZXEgPSByZXF1aXJlKCcuLi8uLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFNlc3Npb25TdG9yZSA9IHJlcXVpcmUoJy4uLy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBVcmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgc2Vzc2lvblN0b3JlID0gbmV3IFNlc3Npb25TdG9yZSh7fSk7XG52YXIgdXJsU2VydmljZSA9IG5ldyBVcmxTZXJ2aWNlKCk7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9rZXktbmFtZXMnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHNlc3Npb25LZXk6IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZLFxuICAgIHBhdGg6ICcnXG59O1xuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBwYXRoKSB7XG4gICAgaWYgKCFwYXRoKSB7XG4gICAgICAgIGlmICghdXJsU2VydmljZS5pc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgICAgICBwYXRoID0gJy8nICsgW3VybFNlcnZpY2UuYXBwUGF0aCwgdXJsU2VydmljZS5hY2NvdW50UGF0aCwgdXJsU2VydmljZS5wcm9qZWN0UGF0aF0uam9pbignLycpO1xuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHdlIGRvbid0IGdldCBjb25zZWN1dGVpdmUgJy8nIHNvIHdlIGhhdmUgYSB2YWxpZCBwYXRoIGZvciB0aGUgc2Vzc2lvblxuICAgICAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZSgvXFwvezIsfS9nLCcvJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYXRoID0gJyc7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gc2V0IHRoZSBzZWVzaW9uS2V5IGZvciB0aGUgcnVuXG4gICAgc2Vzc2lvblN0b3JlLnNldChzZXNzaW9uS2V5LCBKU09OLnN0cmluZ2lmeSh7IHJ1bklkOiBydW4uaWQgfSksIHsgcm9vdDogcGF0aCB9KTtcbn1cblxuLyoqXG4qIENvbmRpdGlvbmFsIENyZWF0aW9uIFN0cmF0ZWd5XG4qIFRoaXMgc3RyYXRlZ3kgd2lsbCB0cnkgdG8gZ2V0IHRoZSBydW4gc3RvcmVkIGluIHRoZSBjb29raWUgYW5kXG4qIGV2YWx1YXRlIGlmIG5lZWRzIHRvIGNyZWF0ZSBhIG5ldyBydW4gYnkgY2FsbGluZyB0aGUgJ2NvbmRpdGlvbicgZnVuY3Rpb25cbiovXG5cbi8qIGpzaGludCBlcW51bGw6IHRydWUgKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KHJ1blNlcnZpY2UsIGNvbmRpdGlvbiwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChjb25kaXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb25kaXRpb25hbCBzdHJhdGVneSBuZWVkcyBhIGNvbmRpdGlvbiB0byBjcmVhdGV0ZSBhIHJ1bicpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fYXV0aCA9IG5ldyBBdXRoTWFuYWdlcigpO1xuICAgICAgICB0aGlzLnJ1biA9IG1ha2VTZXEocnVuU2VydmljZSk7XG4gICAgICAgIHRoaXMuY29uZGl0aW9uID0gdHlwZW9mIGNvbmRpdGlvbiAhPT0gJ2Z1bmN0aW9uJyA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNvbmRpdGlvbjsgfSA6IGNvbmRpdGlvbjtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9LFxuXG4gICAgcnVuT3B0aW9uc1dpdGhTY29wZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdXNlclNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiB1c2VyU2Vzc2lvbi5ncm91cE5hbWUgfVxuICAgICAgICB9LCB0aGlzLnJ1bk9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBvcHQgPSB0aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5ydW5cbiAgICAgICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgc2V0UnVuSW5TZXNzaW9uKF90aGlzLm9wdGlvbnMuc2Vzc2lvbktleSwgcnVuLCBfdGhpcy5vcHRpb25zLnBhdGgpO1xuICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmUuZ2V0KHRoaXMub3B0aW9ucy5zZXNzaW9uS2V5KSk7XG5cbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRBbmRDaGVjayhydW5TZXNzaW9uKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgX2xvYWRBbmRDaGVjazogZnVuY3Rpb24gKHJ1blNlc3Npb24pIHtcbiAgICAgICAgdmFyIHNob3VsZENyZWF0ZSA9IGZhbHNlO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1blxuICAgICAgICAgICAgLmxvYWQocnVuU2Vzc2lvbi5ydW5JZCwgbnVsbCwge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uIChydW4sIG1zZywgaGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBzaG91bGRDcmVhdGUgPSBfdGhpcy5jb25kaXRpb24uY2FsbChfdGhpcywgcnVuLCBoZWFkZXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIGlmIChzaG91bGRDcmVhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9wdCA9IF90aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgbmVlZCB0byBkbyB0aGlzLCBvbiB0aGUgb3JpZ2luYWwgcnVuU2VydmljZSAoaWUgbm90IHNlcXVlbmNpYWxpemVkKVxuICAgICAgICAgICAgICAgICAgICAvLyBzbyB3ZSBkb24ndCBnZXQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1bi5vcmlnaW5hbC5jcmVhdGUob3B0KVxuICAgICAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oX3RoaXMub3B0aW9ucy5zZXNzaW9uS2V5LCBydW4pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnN0YXJ0KCk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSAgPSBydW5TZXJ2aWNlO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSBuZXdseSBjcmVhdGVkIHJ1blxuICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoKS5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSh0aGlzLnJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vaWRlbnRpdHktc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0b3JlOiB7XG4gICAgICAgIHN5bmNocm9ub3VzOiB0cnVlXG4gICAgfVxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcblxuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMud29ybGRBcGkgPSBuZXcgV29ybGRBcGlBZGFwdGVyKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciB3b3JsZEFwaSA9IHRoaXMud29ybGRBcGk7XG4gICAgICAgIHZhciBtb2RlbCA9IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAoIWN1clVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDAsIGVycm9yOiAnV2UgbmVlZCBhbiBhdXRoZW50aWNhdGVkIHVzZXIgdG8gam9pbiBhIG11bHRpcGxheWVyIHdvcmxkLiAoRVJSOiBubyB1c2VySWQgaW4gc2Vzc2lvbiknIH0sIHNlc3Npb24pLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsb2FkUnVuRnJvbVdvcmxkID0gZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDQsIGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IGluIGFueSB3b3JsZC4nIH0sIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oX3RoaXMuX2xvYWRSdW4pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgZHRkLnJlamVjdChlcnJvciwgc2Vzc2lvbiwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIF9sb2FkUnVuOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIFN0YXRlQXBpID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICAgICAgdGhpcy5fc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICAgICAgdGhpcy5zdGF0ZUFwaSA9IG5ldyBTdGF0ZUFwaSgpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZEFuZENoZWNrID0gdGhpcy5fbG9hZEFuZENoZWNrLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVSdW4gPSB0aGlzLl9yZXN0b3JlUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2dldEFsbFJ1bnMgPSB0aGlzLl9nZXRBbGxSdW5zLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0QWxsUnVucygpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9sb2FkQW5kQ2hlY2spO1xuICAgIH0sXG5cbiAgICBfZ2V0QWxsUnVuczogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2UodGhpcy5fc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9Jyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5xdWVyeSh7XG4gICAgICAgICAgICAndXNlci5pZCc6IHNlc3Npb24udXNlcklkIHx8ICcwMDAwJyxcbiAgICAgICAgICAgICdzY29wZS5ncm91cCc6IHNlc3Npb24uZ3JvdXBOYW1lXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVucykge1xuICAgICAgICBpZiAoIXJ1bnMgfHwgIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGVDb21wID0gZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIuZGF0ZSkgLSBuZXcgRGF0ZShhLmRhdGUpOyB9O1xuICAgICAgICB2YXIgbGF0ZXN0UnVuID0gcnVucy5zb3J0KGRhdGVDb21wKVswXTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHNob3VsZFJlcGxheSA9IGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGxhdGVzdFJ1bi5pZCwgbnVsbCwge1xuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVwbGF5ID0gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2hvdWxkUmVwbGF5ID8gX3RoaXMuX3Jlc3RvcmVSdW4ocnVuLmlkKSA6IHJ1bjtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9yZXN0b3JlUnVuOiBmdW5jdGlvbiAocnVuSWQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVBcGkucmVwbGF5KHsgcnVuSWQ6IHJ1bklkIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJ1bihyZXNwLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW4ubG9hZChpZCwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgICduZXctaWYtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLFxuICAgICduZXctaWYtcGVyc2lzdGVkJzogcmVxdWlyZSgnLi9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1taXNzaW5nJzogcmVxdWlyZSgnLi9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpLFxuICAgICdhbHdheXMtbmV3JzogcmVxdWlyZSgnLi9hbHdheXMtbmV3LXN0cmF0ZWd5JyksXG4gICAgJ211bHRpcGxheWVyJzogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdwZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXInOiByZXF1aXJlKCcuL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneScpLFxuICAgICdub25lJzogcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgdmFsaWRGaWx0ZXI6IHsgc2F2ZWQ6IHRydWUgfVxufTtcblxuZnVuY3Rpb24gU2NlbmFyaW9NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMucnVuU2VydmljZSA9IHRoaXMub3B0aW9ucy5ydW4gfHwgbmV3IFJ1blNlcnZpY2UodGhpcy5vcHRpb25zKTtcbn1cblxuU2NlbmFyaW9NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy52YWxpZEZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlcik7XG4gICAgfSxcblxuICAgIGxvYWRWYXJpYWJsZXM6IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UucXVlcnkodGhpcy5maWx0ZXIsIHsgaW5jbHVkZTogdmFycyB9KTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgbWV0YSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2VydmljZShydW4pLnNhdmUoJC5leHRlbmQodHJ1ZSwge30sIHsgc2F2ZWQ6IHRydWUgfSwgbWV0YSkpO1xuICAgIH0sXG5cbiAgICBhcmNoaXZlOiBmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSh7IHNhdmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuXG4gICAgX2dldFNlcnZpY2U6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW4gfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdvYmplY3QnICYmIHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NhdmUgbWV0aG9kIHJlcXVpcmVzIGEgcnVuIHNlcnZpY2Ugb3IgYSBydW5JZCcpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW5JZCB9KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICByZXNldDogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucywgbWFuYWdlcikge1xuICAgICAgICByZXR1cm4gbWFuYWdlci5yZXNldChvcHRpb25zKTtcbiAgICB9XG59O1xuIiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9ICByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG4vLyB2YXIgZGVmYXVsdHMgPSB7XG4vLyAgYWNjb3VudDogJycsXG4vLyAgcHJvamVjdDogJycsXG4vLyAgZ3JvdXA6ICcnLFxuLy8gIHRyYW5zcG9ydDoge1xuLy8gIH1cbi8vIH07XG5cblxuZnVuY3Rpb24gYnVpbGRTdHJhdGVneSh3b3JsZElkLCBkdGQpIHtcblxuICAgIHJldHVybiBmdW5jdGlvbiBDdG9yKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICAkLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm90IGltcGxlbWVudGQuIE5lZWQgYXBpIGNoYW5nZXMnKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlLmNhbGwodGhpcywgcnVuLCBfdGhpcy5ydW5TZXJ2aWNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcklkYCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSBncm91cCBmb3IgdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bih7bW9kZWw6ICdteU1vZGVsLnB5J30pXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBtb2RlbGAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgbW9kZWwgZmlsZS4gUmVxdWlyZWQgaWYgbm90IGFscmVhZHkgcGFzc2VkIGluIGFzIGBydW4ubW9kZWxgIHdoZW4gdGhlIFdvcmxkIE1hbmFnZXIgaXMgY3JlYXRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgX3RoaXMub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJtLmdldFJ1bigpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHJ1biwgcm0ucnVuU2VydmljZSwgcm0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5nZXRDdXJyZW50V29ybGQoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bik7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIGFwaSk7XG59O1xuIiwiLyoqXG4gKiAjI0ZpbGUgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGlzIGlzIHVzZWQgdG8gdXBsb2FkL2Rvd25sb2FkIGZpbGVzIGRpcmVjdGx5IG9udG8gRXBpY2VudGVyLCBhbmFsb2dvdXMgdG8gdXNpbmcgdGhlIEZpbGUgTWFuYWdlciBVSSBpbiBFcGljZW50ZXIgZGlyZWN0bHkgb3IgU0ZUUGluZyBmaWxlcyBpbi4gVGhlIEFzc2V0IEFQSSBpcyB0eXBpY2FsbHkgdXNlZCBmb3IgYWxsIHByb2plY3QgdXNlLWNhc2VzLCBhbmQgaXQncyB1bmxpa2VseSB0aGlzIEZpbGUgU2VydmljZSB3aWxsIGJlIHVzZWQgZGlyZWN0bHkgZXhjZXB0IGJ5IEFkbWluIHRvb2xzIChlLmcuIEZsb3cgSW5zcGVjdG9yKS5cbiAqXG4gKiBQYXJ0aWFsbHkgaW1wbGVtZW50ZWQuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCBzdG9yZS5nZXQoJ2VwaWNlbnRlci50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZmlsZScpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQXN5bmNBUEkgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgYSBkaXJlY3RvcnkgbGlzdGluZywgb3IgY29udGVudHMgb2YgYSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGZpbGVQYXRoYCAgIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZm9sZGVyVHlwZWAgT25lIG9mIE1vZGVsfFN0YXRpY3xOb2RlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBnZXRDb250ZW50czogZnVuY3Rpb24gKGZpbGVQYXRoLCBmb2xkZXJUeXBlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IGZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbi8vIHZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGtleU5hbWVzID0gcmVxdWlyZSgnLi4vbWFuYWdlcnMva2V5LW5hbWVzJyk7XG5cbnZhciBhcGlFbmRwb2ludCA9ICdhc3NldCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZShzdG9yZS5nZXQoa2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZKSB8fCAne30nKTtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9DT09LSUVfS0VZKSB8fCAnJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gRGVmYXVsdHMgdG8gc2Vzc2lvbidzIGBncm91cE5hbWVgLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogc2Vzc2lvbi51c2VySWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgc2NvcGUgZm9yIHRoZSBhc3NldC4gVmFsaWQgdmFsdWVzIGFyZTogYHVzZXJgLCBgZ3JvdXBgLCBhbmQgYHByb2plY3RgLiBTZWUgYWJvdmUgZm9yIHRoZSByZXF1aXJlZCBwZXJtaXNzaW9ucyB0byB3cml0ZSB0byBlYWNoIHNjb3BlLiBEZWZhdWx0cyB0byBgdXNlcmAsIG1lYW5pbmcgdGhlIGN1cnJlbnQgZW5kIHVzZXIgb3IgYSBmYWNpbGl0YXRvciBpbiB0aGUgZW5kIHVzZXIncyBncm91cCBjYW4gZWRpdCB0aGUgYXNzZXQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBzY29wZTogJ3VzZXInLFxuICAgICAgICAvKipcbiAgICAgICAgICogRGV0ZXJtaW5lcyBpZiBhIHJlcXVlc3QgdG8gbGlzdCB0aGUgYXNzZXRzIGluIGEgc2NvcGUgaW5jbHVkZXMgdGhlIGNvbXBsZXRlIFVSTCBmb3IgZWFjaCBhc3NldCAoYHRydWVgKSwgb3Igb25seSB0aGUgZmlsZSBuYW1lcyBvZiB0aGUgYXNzZXRzIChgZmFsc2VgKS4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGZ1bGxVcmw6IHRydWUsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgdHJhbnNwb3J0IG9iamVjdCBjb250YWlucyB0aGUgb3B0aW9ucyBwYXNzZWQgdG8gdGhlIFhIUiByZXF1ZXN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7XG4gICAgICAgICAgICBwcm9jZXNzRGF0YTogZmFsc2VcbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIGFzc2V0QXBpUGFyYW1zID0gWydlbmNvZGluZycsICdkYXRhJywgJ2NvbnRlbnRUeXBlJ107XG4gICAgdmFyIHNjb3BlQ29uZmlnID0ge1xuICAgICAgICB1c2VyOiBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSxcbiAgICAgICAgZ3JvdXA6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10sXG4gICAgICAgIHByb2plY3Q6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0J10sXG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZUZpbGVuYW1lID0gZnVuY3Rpb24gKGZpbGVuYW1lKSB7XG4gICAgICAgIGlmICghZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZmlsZW5hbWUgaXMgbmVlZGVkLicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZVVybFBhcmFtcyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICBpZiAoIXBhcnRLZXlzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Njb3BlIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cblxuICAgICAgICAkLmVhY2gocGFydEtleXMsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICghb3B0aW9uc1t0aGlzXSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzICsgJyBwYXJhbWV0ZXIgaXMgbmVlZGVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgdmFyIGJ1aWxkVXJsID0gZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgIHZhbGlkYXRlVXJsUGFyYW1zKG9wdGlvbnMpO1xuICAgICAgICB2YXIgcGFydEtleXMgPSBzY29wZUNvbmZpZ1tvcHRpb25zLnNjb3BlXTtcbiAgICAgICAgdmFyIHBhcnRzID0gJC5tYXAocGFydEtleXMsIGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zW2tleV07XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgcHJldmVudHMgYWRkaW5nIGEgdHJhaWxpbmcgLyBpbiB0aGUgVVJMIGFzIHRoZSBBc3NldCBBUElcbiAgICAgICAgICAgIC8vIGRvZXMgbm90IHdvcmsgY29ycmVjdGx5IHdpdGggaXRcbiAgICAgICAgICAgIGZpbGVuYW1lID0gJy8nICsgZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHBhcnRzLmpvaW4oJy8nKSArIGZpbGVuYW1lO1xuICAgIH07XG5cbiAgICAvLyBQcml2YXRlIGZ1bmN0aW9uLCBhbGwgcmVxdWVzdHMgZm9sbG93IGEgbW9yZSBvciBsZXNzIHNhbWUgYXBwcm9hY2ggdG9cbiAgICAvLyB1c2UgdGhlIEFzc2V0IEFQSSBhbmQgdGhlIGRpZmZlcmVuY2UgaXMgdGhlIEhUVFAgdmVyYlxuICAgIC8vXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBtZXRob2RgIChSZXF1aXJlZCkgSFRUUCB2ZXJiXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS9yZXBsYWNlL2NyZWF0ZVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUElcbiAgICAvLyBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgdmFyIHVwbG9hZCA9IGZ1bmN0aW9uIChtZXRob2QsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVGaWxlbmFtZShmaWxlbmFtZSk7XG4gICAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgcGFyYW1ldGVyIGlzIGNsZWFuXG4gICAgICAgIG1ldGhvZCA9IG1ldGhvZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB2YXIgY29udGVudFR5cGUgPSBwYXJhbXMgaW5zdGFuY2VvZiBGb3JtRGF0YSA9PT0gdHJ1ZSA/IGZhbHNlIDogJ2FwcGxpY2F0aW9uL2pzb24nO1xuICAgICAgICBpZiAoY29udGVudFR5cGUgPT09ICdhcHBsaWNhdGlvbi9qc29uJykge1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIGFzc2V0QXBpUGFyYW1zKTtcbiAgICAgICAgfSBlbHNlIHsgLy8gZWxzZSB3ZSdyZSBzZW5kaW5nIGZvcm0gZGF0YSB3aGljaCBnb2VzIGRpcmVjdGx5IGluIHJlcXVlc3QgYm9keVxuICAgICAgICAgICAgLy8gRm9yIG11bHRpcGFydC9mb3JtLWRhdGEgdXBsb2FkcyB0aGUgZmlsZW5hbWUgaXMgbm90IHNldCBpbiB0aGUgVVJMLFxuICAgICAgICAgICAgLy8gaXQncyBnZXR0aW5nIHBpY2tlZCBieSB0aGUgRm9ybURhdGEgZmllbGQgZmlsZW5hbWUuXG4gICAgICAgICAgICBmaWxlbmFtZSA9IG1ldGhvZCA9PT0gJ3Bvc3QnIHx8IG1ldGhvZCA9PT0gJ3B1dCcgPyAnJyA6IGZpbGVuYW1lO1xuICAgICAgICB9XG4gICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCwgY29udGVudFR5cGU6IGNvbnRlbnRUeXBlIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwW21ldGhvZF0ocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS4gVGhlIHNlcnZlciByZXR1cm5zIGFuIGVycm9yIChzdGF0dXMgY29kZSBgNDA5YCwgY29uZmxpY3QpIGlmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLCBzb1xuICAgICAgICAqIGNoZWNrIGZpcnN0IHdpdGggYSBgbGlzdCgpYCBvciBhIGBnZXQoKWAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBhYSA9IG5ldyBGLnNlcnZpY2UuQXNzZXQoe1xuICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAgICAqICAgICAgICAgIHVzZXJJZDogJydcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAgICAgICAgKiAgICAgICBhYS5jcmVhdGUoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gICAgICAgICogICAgICAgICAgIGNvbnRlbnRUeXBlOiAndGV4dC9wbGFpbidcbiAgICAgICAgKiAgICAgICB9LCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyBhbHRlcm5hdGl2ZWx5LCBjcmVhdGUgYSBuZXcgYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJ1cGxvYWQtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5VcGxvYWQgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3VwbG9hZC1maWxlJykub24oJ3N1Ym1pdCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLmNyZWF0ZShmaWxlbmFtZSwgZGF0YSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gY3JlYXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUEkuIFJlcXVpcmVkIGlmIHRoZSBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYCwgb3RoZXJ3aXNlIGlnbm9yZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZW5jb2RpbmdgIEVpdGhlciBgSEVYYCBvciBgQkFTRV82NGAuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmRhdGFgIFRoZSBlbmNvZGVkIGRhdGEgZm9yIHRoZSBmaWxlLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5jb250ZW50VHlwZWAgVGhlIG1pbWUgdHlwZSBvZiB0aGUgZmlsZS4gT3B0aW9uYWwuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3Bvc3QnLCBmaWxlbmFtZSwgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGEgZmlsZSBmcm9tIHRoZSBBc3NldCBBUEksIGZldGNoaW5nIHRoZSBhc3NldCBjb250ZW50LiAoVG8gZ2V0IGEgbGlzdFxuICAgICAgICAqIG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZSwgdXNlIGBsaXN0KClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byByZXRyaWV2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBnZXRTZXJ2aWNlT3B0aW9ucyA9IF9waWNrKHNlcnZpY2VPcHRpb25zLCBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSk7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBnZXRTZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBsaXN0IG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5saXN0KHsgZnVsbFVybDogdHJ1ZSB9KS50aGVuKGZ1bmN0aW9uKGZpbGVMaXN0KXtcbiAgICAgICAgKiAgICAgICAgICAgY29uc29sZS5sb2coJ2FycmF5IG9mIGZpbGVzID0gJywgZmlsZUxpc3QpO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5zY29wZWAgKE9wdGlvbmFsKSBUaGUgc2NvcGUgKGB1c2VyYCwgYGdyb3VwYCwgYHByb2plY3RgKS5cbiAgICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGBvcHRpb25zLmZ1bGxVcmxgIChPcHRpb25hbCkgRGV0ZXJtaW5lcyBpZiB0aGUgbGlzdCBvZiBhc3NldHMgaW4gYSBzY29wZSBpbmNsdWRlcyB0aGUgY29tcGxldGUgVVJMIGZvciBlYWNoIGFzc2V0IChgdHJ1ZWApLCBvciBvbmx5IHRoZSBmaWxlIG5hbWVzIG9mIHRoZSBhc3NldHMgKGBmYWxzZWApLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybCgnJywgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuICAgICAgICAgICAgdmFyIGZ1bGxVcmwgPSBnZXRPcHRpb25zLmZ1bGxVcmw7XG5cbiAgICAgICAgICAgIGlmICghZnVsbFVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZnVsbFBhdGhGaWxlcyA9ICQubWFwKGZpbGVzLCBmdW5jdGlvbiAoZmlsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoZnVsbFBhdGhGaWxlcywgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlcGxhY2VzIGFuIGV4aXN0aW5nIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyByZXBsYWNlIGFuIGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLnJlcGxhY2UoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhObFkyOXVaQ0IwWlhOMElHWnBiR1V1JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJyZXBsYWNlLWZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwicmVwbGFjZS1maWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5SZXBsYWNlIG15RmlsZTwvYnV0dG9uPlxuICAgICAgICAqICAgICAgIC8vIDwvZm9ybT5cbiAgICAgICAgKiAgICAgICAvL1xuICAgICAgICAqICAgICAgICQoJyNyZXBsYWNlLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI3JlcGxhY2UtZmlsZW5hbWUnKS52YWwoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICAgICAgICAqICAgICAgICAgIGRhdGEuYXBwZW5kKCdmaWxlJywgaW5wdXRDb250cm9sLmZpbGVzWzBdLCBmaWxlbmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICBhYS5yZXBsYWNlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgYmVpbmcgcmVwbGFjZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgcmVwbGFjZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3B1dCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5kZWxldGUoc2FtcGxlRmlsZU5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ2RlbGV0ZScsIGZpbGVuYW1lLCB7fSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYXNzZXRVcmw6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlIHByb3ZpZGVzIG1ldGhvZHMgZm9yIGxvZ2dpbmcgaW4gYW5kIGxvZ2dpbmcgb3V0LiBPbiBsb2dpbiwgdGhpcyBzZXJ2aWNlIGNyZWF0ZXMgYW5kIHJldHVybnMgYSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAqXG4gKiBVc2VyIGFjY2VzcyB0b2tlbnMgYXJlIHJlcXVpcmVkIGZvciBlYWNoIGNhbGwgdG8gRXBpY2VudGVyLiAoU2VlIFtQcm9qZWN0IEFjY2Vzc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4pXG4gKlxuICogSWYgeW91IG5lZWQgYWRkaXRpb25hbCBmdW5jdGlvbmFsaXR5IC0tIHN1Y2ggYXMgdHJhY2tpbmcgc2Vzc2lvbiBpbmZvcm1hdGlvbiwgZWFzaWx5IHJldHJpZXZpbmcgdGhlIHVzZXIgdG9rZW4sIG9yIGdldHRpbmcgdGhlIGdyb3VwcyB0byB3aGljaCBhbiBlbmQgdXNlciBiZWxvbmdzIC0tIGNvbnNpZGVyIHVzaW5nIHRoZSBbQXV0aG9yaXphdGlvbiBNYW5hZ2VyXSguLi9hdXRoLW1hbmFnZXIvKSBpbnN0ZWFkLlxuICpcbiAqICAgICAgdmFyIGF1dGggPSBuZXcgRi5zZXJ2aWNlLkF1dGgoKTtcbiAqICAgICAgYXV0aC5sb2dpbih7IHVzZXJOYW1lOiAnanNtaXRoQGFjbWVzaW11bGF0aW9ucy5jb20nLFxuICogICAgICAgICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyB9KTtcbiAqICAgICAgYXV0aC5sb2dvdXQoKTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VyTmFtZTogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFzc3dvcmQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gUmVxdWlyZWQgaWYgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdhdXRoZW50aWNhdGlvbicpXG4gICAgfSk7XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvZ3MgdXNlciBpbiwgcmV0dXJuaW5nIHRoZSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAgICAgICAgICpcbiAgICAgICAgICogSWYgbm8gYHVzZXJOYW1lYCBvciBgcGFzc3dvcmRgIHdlcmUgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLCB0aGV5IGFyZSByZXF1aXJlZCBpbiB0aGUgYG9wdGlvbnNgIGhlcmUuIElmIG5vIGBhY2NvdW50YCB3YXMgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zIGFuZCB0aGUgYHVzZXJOYW1lYCBpcyBmb3IgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGUgYGFjY291bnRgIGlzIHJlcXVpcmVkIGFzIHdlbGwuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgYXV0aC5sb2dpbih7XG4gICAgICAgICAqICAgICAgICAgIHVzZXJOYW1lOiAnanNtaXRoJyxcbiAgICAgICAgICogICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcsXG4gICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyB9KVxuICAgICAgICAgKiAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhcInVzZXIgYWNjZXNzIHRva2VuIGlzOiBcIiwgdG9rZW4uYWNjZXNzX3Rva2VuKTtcbiAgICAgICAgICogICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHN1Y2Nlc3M6ICQubm9vcCB9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBpZiAoIWh0dHBPcHRpb25zLnVzZXJOYW1lIHx8ICFodHRwT3B0aW9ucy5wYXNzd29yZCkge1xuICAgICAgICAgICAgICAgIHZhciByZXNwID0geyBzdGF0dXM6IDQwMSwgc3RhdHVzTWVzc2FnZTogJ05vIHVzZXJuYW1lIG9yIHBhc3N3b3JkIHNwZWNpZmllZC4nIH07XG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvci5jYWxsKHRoaXMsIHJlc3ApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVqZWN0KHJlc3ApLnByb21pc2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHBvc3RQYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgdXNlck5hbWU6IGh0dHBPcHRpb25zLnVzZXJOYW1lLFxuICAgICAgICAgICAgICAgIHBhc3N3b3JkOiBodHRwT3B0aW9ucy5wYXNzd29yZCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoaHR0cE9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vcGFzcyBpbiBudWxsIGZvciBhY2NvdW50IHVuZGVyIG9wdGlvbnMgaWYgeW91IGRvbid0IHdhbnQgaXQgdG8gYmUgc2VudFxuICAgICAgICAgICAgICAgIHBvc3RQYXJhbXMuYWNjb3VudCA9IGh0dHBPcHRpb25zLmFjY291bnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocG9zdFBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2dzIHVzZXIgb3V0IGZyb20gc3BlY2lmaWVkIGFjY291bnRzLlxuICAgICAgICAgKiBFcGljZW50ZXIgbG9nb3V0IGlzIG5vdCBpbXBsZW1lbnRlZCB5ZXQsIGFkZGVkIGEgZHVtbXkgcHJvbWlzZSB0aGF0IGdldHMgYXV0b21hdGljYWxseSByZXNvbHZlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBhdXRoLmxvZ291dCgpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2dvdXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgZHRkLnJlc29sdmUoKTtcbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqICMjIENoYW5uZWwgU2VydmljZVxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBDaGFubmVsIFNlcnZpY2UgaXMgYSBidWlsZGluZyBibG9jayBmb3IgdGhpcyBmdW5jdGlvbmFsaXR5LiBJdCBjcmVhdGVzIGEgcHVibGlzaC1zdWJzY3JpYmUgb2JqZWN0LCBhbGxvd2luZyB5b3UgdG8gcHVibGlzaCBtZXNzYWdlcywgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzLCBvciB1bnN1YnNjcmliZSBmcm9tIG1lc3NhZ2VzIGZvciBhIGdpdmVuICd0b3BpYycgb24gYSBgJC5jb21ldGRgIHRyYW5zcG9ydCBpbnN0YW5jZS5cbiAqXG4gKiBUeXBpY2FsbHksIHlvdSB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgdG8gY3JlYXRlIG9yIHJldHJpZXZlIGNoYW5uZWxzLCB0aGVuIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gbGlzdGVuIHRvIG9yIHVwZGF0ZSBkYXRhLiAoRm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZCBvbiBFcGljZW50ZXIncyBwdXNoIGNoYW5uZWwsIHNlZSB0aGUgaW50cm9kdWN0b3J5IG5vdGVzIG9uIHRoZSBbUHVzaCBDaGFubmVsIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvKSBwYWdlLilcbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UuIFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLlxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCwgdGhlbiBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbiAqXG4gKiAgICAgICAgdmFyIGNzID0gbmV3IEYuc2VydmljZS5DaGFubmVsKCk7XG4gKiAgICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgU2VydmljZSBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgU2VydmljZS5cbiAqICogYG9wdGlvbnMuYmFzZWAgVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLnRvcGljUmVzb2x2ZXJgIEEgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgYWxsICd0b3BpY3MnIHBhc3NlZCBpbnRvIHRoZSBgcHVibGlzaGAgYW5kIGBzdWJzY3JpYmVgIG1ldGhvZHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGltcGxlbWVudCB5b3VyIG93biBzZXJpYWxpemUgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGN1c3RvbSBvYmplY3RzIHRvIHRvcGljIG5hbWVzLiBSZXR1cm5zIGEgU3RyaW5nLiBCeSBkZWZhdWx0LCBpdCBqdXN0IGVjaG9lcyB0aGUgdG9waWMuXG4gKiAqIGBvcHRpb25zLnRyYW5zcG9ydGAgVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLiBTZWUgaHR0cDovL2RvY3MuY29tZXRkLm9yZy9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gY29tZXRkLlxuICovXG52YXIgQ2hhbm5lbCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYmFzZSB0b3BpYy4gVGhpcyBpcyBhZGRlZCBhcyBhIHByZWZpeCB0byBhbGwgZnVydGhlciB0b3BpY3MgeW91IHB1Ymxpc2ggb3Igc3Vic2NyaWJlIHRvIHdoaWxlIHdvcmtpbmcgd2l0aCB0aGlzIENoYW5uZWwgU2VydmljZS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGJhc2U6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqIGB0b3BpY2AgVG9waWMgdG8gcGFyc2UuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiAqU3RyaW5nKjogVGhpcyBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIGEgc3RyaW5nIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICB0b3BpY1Jlc29sdmVyOiBmdW5jdGlvbiAodG9waWMpIHtcbiAgICAgICAgICAgIHJldHVybiB0b3BpYztcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiBudWxsXG4gICAgfTtcbiAgICB0aGlzLmNoYW5uZWxPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbn07XG5cbnZhciBtYWtlTmFtZSA9IGZ1bmN0aW9uIChjaGFubmVsTmFtZSwgdG9waWMpIHtcbiAgICAvL1JlcGxhY2UgdHJhaWxpbmcvZG91YmxlIHNsYXNoZXNcbiAgICB2YXIgbmV3TmFtZSA9IChjaGFubmVsTmFtZSA/IChjaGFubmVsTmFtZSArICcvJyArIHRvcGljKSA6IHRvcGljKS5yZXBsYWNlKC9cXC9cXC8vZywgJy8nKS5yZXBsYWNlKC9cXC8kLywnJyk7XG4gICAgcmV0dXJuIG5ld05hbWU7XG59O1xuXG5cbkNoYW5uZWwucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbC5wcm90b3R5cGUsIHtcblxuICAgIC8vIGZ1dHVyZSBmdW5jdGlvbmFsaXR5OlxuICAgIC8vICAgICAgLy8gU2V0IHRoZSBjb250ZXh0IGZvciB0aGUgY2FsbGJhY2tcbiAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgZnVuY3Rpb24gKCkgeyB0aGlzLmlubmVySFRNTCA9ICdUcmlnZ2VyZWQnfSwgZG9jdW1lbnQuYm9keSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gQ29udHJvbCB0aGUgb3JkZXIgb2Ygb3BlcmF0aW9ucyBieSBzZXR0aW5nIHRoZSBgcHJpb3JpdHlgXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4nLCBjYiwgdGhpcywge3ByaW9yaXR5OiA5fSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIDUwXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiA1MH0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBncmVhdGVyIHRoYW4gNTBcbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6ICc+NTAnfSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIGV2ZW5cbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6IGZ1bmN0aW9uICh2YWwpIHtyZXR1cm4gdmFsICUgMiA9PT0gMH19KTtcblxuXG4gICAgLyoqXG4gICAgICogU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqIFRoZSB0b3BpYyBzaG91bGQgaW5jbHVkZSB0aGUgZnVsbCBwYXRoIG9mIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cyksIHByb2plY3QgaWQsIGFuZCBncm91cCBuYW1lLiAoSW4gbW9zdCBjYXNlcywgaXQgaXMgc2ltcGxlciB0byB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgaW5zdGVhZCwgaW4gd2hpY2ggY2FzZSB0aGlzIGlzIGNvbmZpZ3VyZWQgZm9yIHlvdS4pXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlcyoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjYiA9IGZ1bmN0aW9uKHZhbCkgeyBjb25zb2xlLmxvZyh2YWwuZGF0YSk7IH07XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9wLWxldmVsICdydW4nIHRvcGljXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGNoaWxkcmVuIG9mIHRoZSAncnVuJyB0b3BpYy4gTm90ZSB0aGlzIHdpbGwgYWxzbyBiZSB0cmlnZ2VyZWQgZm9yIGNoYW5nZXMgdG8gcnVuLngueS56LlxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuLyonLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGJvdGggdGhlIHRvcC1sZXZlbCAncnVuJyB0b3BpYyBhbmQgaXRzIGNoaWxkcmVuXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoWycvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJyxcbiAgICAgKiAgICAgICAgICAnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJ10sIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSBwYXJ0aWN1bGFyIHZhcmlhYmxlXG4gICAgICogICAgICBzdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzL3ByaWNlJywgY2IpO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpTdHJpbmcqIFJldHVybnMgYSB0b2tlbiB5b3UgY2FuIGxhdGVyIHVzZSB0byB1bnN1YnNjcmliZS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfEFycmF5fSAgIGB0b3BpY2AgICAgTGlzdCBvZiB0b3BpY3MgdG8gbGlzdGVuIGZvciBjaGFuZ2VzIG9uLlxuICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBgY2FsbGJhY2tgIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGV4ZWN1dGUuIENhbGxiYWNrIGlzIGNhbGxlZCB3aXRoIHNpZ25hdHVyZSBgKGV2dCwgcGF5bG9hZCwgbWV0YWRhdGEpYC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgYGNvbnRleHRgICBDb250ZXh0IGluIHdoaWNoIHRoZSBgY2FsbGJhY2tgIGlzIGV4ZWN1dGVkLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gICBgb3B0aW9uc2AgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICogQHBhcmFtICB7TnVtYmVyfSAgIGBvcHRpb25zLnByaW9yaXR5YCAgVXNlZCB0byBjb250cm9sIG9yZGVyIG9mIG9wZXJhdGlvbnMuIERlZmF1bHRzIHRvIDAuIENhbiBiZSBhbnkgK3ZlIG9yIC12ZSBudW1iZXIuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE51bWJlcnxGdW5jdGlvbn0gICBgb3B0aW9ucy52YWx1ZWAgVGhlIGBjYWxsYmFja2AgaXMgb25seSB0cmlnZ2VyZWQgaWYgdGhpcyBjb25kaXRpb24gbWF0Y2hlcy4gU2VlIGV4YW1wbGVzIGZvciBkZXRhaWxzLlxuICAgICAqXG4gICAgICovXG4gICAgc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9waWMsIGNhbGxiYWNrLCBjb250ZXh0LCBvcHRpb25zKSB7XG5cbiAgICAgICAgdmFyIHRvcGljcyA9IFtdLmNvbmNhdCh0b3BpYyk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBzdWJzY3JpcHRpb25JZHMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuICAgICAgICBvcHRzLnRyYW5zcG9ydC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkLmVhY2godG9waWNzLCBmdW5jdGlvbiAoaW5kZXgsIHRvcGljKSB7XG4gICAgICAgICAgICAgICAgdG9waWMgPSBtYWtlTmFtZShvcHRzLmJhc2UsIG9wdHMudG9waWNSZXNvbHZlcih0b3BpYykpO1xuICAgICAgICAgICAgICAgIHN1YnNjcmlwdGlvbklkcy5wdXNoKG9wdHMudHJhbnNwb3J0LnN1YnNjcmliZSh0b3BpYywgY2FsbGJhY2spKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChzdWJzY3JpcHRpb25JZHNbMV0gPyBzdWJzY3JpcHRpb25JZHMgOiBzdWJzY3JpcHRpb25JZHNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBQdWJsaXNoIGRhdGEgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICAvLyBTZW5kIGRhdGEgdG8gYWxsIHN1YnNjcmliZXJzIG9mIHRoZSAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsIHsgY29tcGxldGVkOiBmYWxzZSB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bi92YXJpYWJsZXMnIHRvcGljXG4gICAgICogICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcycsIHsgcHJpY2U6IDUwIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRvcGljYCBUb3BpYyB0byBwdWJsaXNoIHRvLlxuICAgICAqIEBwYXJhbSAgeyp9IGBkYXRhYCAgRGF0YSB0byBwdWJsaXNoIHRvIHRvcGljLlxuICAgICAqXG4gICAgICovXG4gICAgcHVibGlzaDogZnVuY3Rpb24gKHRvcGljLCBkYXRhKSB7XG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgcmV0dXJuT2JqcyA9IFtdO1xuICAgICAgICB2YXIgb3B0cyA9IG1lLmNoYW5uZWxPcHRpb25zO1xuXG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBpZiAodG9waWMuY2hhckF0KHRvcGljLmxlbmd0aCAtIDEpID09PSAnKicpIHtcbiAgICAgICAgICAgICAgICAgICAgdG9waWMgPSB0b3BpYy5yZXBsYWNlKC9cXCorJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdZb3UgY2FuIGNhbm5vdCBwdWJsaXNoIHRvIGNoYW5uZWxzIHdpdGggd2lsZGNhcmRzLiBQdWJsaXNoaW5nIHRvICcsIHRvcGljLCAnaW5zdGVhZCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpzLnB1c2gob3B0cy50cmFuc3BvcnQucHVibGlzaCh0b3BpYywgZGF0YSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKHJldHVybk9ianNbMV0gPyByZXR1cm5PYmpzIDogcmV0dXJuT2Jqc1swXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVuc3Vic2NyaWJlIGZyb20gY2hhbmdlcyB0byBhIHRvcGljLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgY3MudW5zdWJzY3JpYmUoJ3NhbXBsZVRva2VuJyk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRva2VuYCBUaGUgdG9rZW4gZm9yIHRvcGljIGlzIHJldHVybmVkIHdoZW4geW91IGluaXRpYWxseSBzdWJzY3JpYmUuIFBhc3MgaXQgaGVyZSB0byB1bnN1YnNjcmliZSBmcm9tIHRoYXQgdG9waWMuXG4gICAgICovXG4gICAgdW5zdWJzY3JpYmU6IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICB0aGlzLmNoYW5uZWxPcHRpb25zLnRyYW5zcG9ydC51bnN1YnNjcmliZSh0b2tlbik7XG4gICAgICAgIHJldHVybiB0b2tlbjtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICpcbiAgICAgKiBTdXBwb3J0ZWQgZXZlbnRzIGFyZTogYGNvbm5lY3RgLCBgZGlzY29ubmVjdGAsIGBzdWJzY3JpYmVgLCBgdW5zdWJzY3JpYmVgLCBgcHVibGlzaGAsIGBlcnJvcmAuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqL1xuICAgIG9uOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vbi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdG9wIGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqL1xuICAgIG9mZjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub2ZmLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZXZlbnRzIGFuZCBleGVjdXRlIGhhbmRsZXJzLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqL1xuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENoYW5uZWw7XG4iLCIvKipcbiAqIEBjbGFzcyBDb25maWd1cmF0aW9uU2VydmljZVxuICpcbiAqIEFsbCBzZXJ2aWNlcyB0YWtlIGluIGEgY29uZmlndXJhdGlvbiBzZXR0aW5ncyBvYmplY3QgdG8gY29uZmlndXJlIHRoZW1zZWx2ZXMuIEEgSlMgaGFzaCB7fSBpcyBhIHZhbGlkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCBidXQgb3B0aW9uYWxseSB5b3UgY2FuIHVzZSB0aGUgY29uZmlndXJhdGlvbiBzZXJ2aWNlIHRvIHRvZ2dsZSBjb25maWdzIGJhc2VkIG9uIHRoZSBlbnZpcm9ubWVudFxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgdmFyIGNzID0gcmVxdWlyZSgnY29uZmlndXJhdGlvbi1zZXJ2aWNlJykoe1xuICogICAgICAgICAgZGV2OiB7IC8vZW52aXJvbm1lbnRcbiAgICAgICAgICAgICAgICBwb3J0OiAzMDAwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdsb2NhbGhvc3QnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHByb2Q6IHtcbiAgICAgICAgICAgICAgICBwb3J0OiA4MDgwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgICAgICAgICBsb2dMZXZlbDogJ25vbmUnXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbG9nTGV2ZWw6ICdERUJVRycgLy9nbG9iYWxcbiAqICAgICB9KTtcbiAqXG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudignZGV2Jyk7XG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudigncHJvZCcpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnbm9uZSdcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHVybFNlcnZpY2UgPSByZXF1aXJlKCcuL3VybC1jb25maWctc2VydmljZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IEVudmlyb25tZW50c1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgbG9nTGV2ZWw6ICdOT05FJ1xuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHNlcnZpY2VPcHRpb25zLnNlcnZlciA9IHVybFNlcnZpY2Uoc2VydmljZU9wdGlvbnMuc2VydmVyKTtcblxuICAgIHJldHVybiB7XG5cbiAgICAgICAgZGF0YTogc2VydmljZU9wdGlvbnMsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgZW52aXJvbm1lbnQga2V5IHRvIGdldCBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbVxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGVudlxuICAgICAgICAgKi9cbiAgICAgICAgc2V0RW52OiBmdW5jdGlvbiAoZW52KSB7XG5cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHByb3BlcnR5IG9wdGlvbmFsXG4gICAgICAgICAqIEByZXR1cm4geyp9ICAgICAgICAgIFZhbHVlIG9mIHByb3BlcnR5IGlmIHNwZWNpZmllZCwgdGhlIGVudGlyZSBjb25maWcgb2JqZWN0IG90aGVyd2lzZVxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9uc1twcm9wZXJ0eV07XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5IGlmIGEga2V5IGlzIHByb3ZpZGVkLCBzZXQgYSBrZXkgdG8gdGhhdCB2YWx1ZS4gT3RoZXJ3aXNlIG1lcmdlIG9iamVjdCB3aXRoIGN1cnJlbnQgY29uZmlnXG4gICAgICAgICAqIEBwYXJhbSAgeyp9IHZhbHVlICB2YWx1ZSBmb3IgcHJvdmlkZWQga2V5XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9uc1trZXldID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9O1xufTtcblxuIiwiLyoqXG4gKiAjI0RhdGEgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgRGF0YSBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgbWFuaXB1bGF0ZSBkYXRhIHJlbGF0ZWQgdG8gYW55IG9mIHlvdXIgcHJvamVjdHMuIERhdGEgYXJlIG9yZ2FuaXplZCBpbiBjb2xsZWN0aW9ucy4gRWFjaCBjb2xsZWN0aW9uIGNvbnRhaW5zIGEgZG9jdW1lbnQ7IGVhY2ggZWxlbWVudCBvZiB0aGlzIHRvcC1sZXZlbCBkb2N1bWVudCBpcyBhIEpTT04gb2JqZWN0LiAoU2VlIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gb24gdGhlIHVuZGVybHlpbmcgW0RhdGEgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvZGF0YV9hcGkvKS4pXG4gKlxuICogQWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgRGF0YSBBUEkgU2VydmljZSBkZWZhdWx0cy4gSW4gcGFydGljdWxhciwgdGhlcmUgYXJlIHRocmVlIHJlcXVpcmVkIHBhcmFtZXRlcnMgd2hlbiB5b3UgaW5zdGFudGlhdGUgdGhlIERhdGEgU2VydmljZTpcbiAqXG4gKiAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgcHJvamVjdGA6IEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICogKiBgcm9vdGA6IFRoZSB0aGUgbmFtZSBvZiB0aGUgY29sbGVjdGlvbi4gSWYgeW91IGhhdmUgbXVsdGlwbGUgY29sbGVjdGlvbnMgd2l0aGluIGVhY2ggb2YgeW91ciBwcm9qZWN0cywgeW91IGNhbiBhbHNvIHBhc3MgdGhlIGNvbGxlY3Rpb24gbmFtZSBhcyBhbiBvcHRpb24gZm9yIGVhY2ggY2FsbC5cbiAqXG4gKiAgICAgICB2YXIgZHMgPSBuZXcgRi5zZXJ2aWNlLkRhdGEoe1xuICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgIHJvb3Q6ICdzdXJ2ZXktcmVzcG9uc2VzJyxcbiAqICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBkcy5zYXZlQXMoJ3VzZXIxJyxcbiAqICAgICAgICAgIHsgJ3F1ZXN0aW9uMSc6IDIsICdxdWVzdGlvbjInOiAxMCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiBmYWxzZSwgJ3F1ZXN0aW9uNCc6ICdzb21ldGltZXMnIH0gKTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjInLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMywgJ3F1ZXN0aW9uMic6IDgsXG4gKiAgICAgICAgICAncXVlc3Rpb24zJzogdHJ1ZSwgJ3F1ZXN0aW9uNCc6ICdhbHdheXMnIH0gKTtcbiAqICAgICAgIGRzLnF1ZXJ5KCcnLHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICpcbiAqIE5vdGUgdGhhdCBpbiBhZGRpdGlvbiB0byB0aGUgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgcm9vdGAsIHRoZSBEYXRhIFNlcnZpY2UgcGFyYW1ldGVycyBvcHRpb25hbGx5IGluY2x1ZGUgYSBgc2VydmVyYCBvYmplY3QsIHdob3NlIGBob3N0YCBmaWVsZCBjb250YWlucyB0aGUgVVJJIG9mIHRoZSBGb3JpbyBzZXJ2ZXIuIFRoaXMgaXMgYXV0b21hdGljYWxseSBzZXQsIGJ1dCB5b3UgY2FuIHBhc3MgaXQgZXhwbGljaXRseSBpZiBkZXNpcmVkLiBJdCBpcyBtb3N0IGNvbW1vbmx5IHVzZWQgZm9yIGNsYXJpdHkgd2hlbiB5b3UgYXJlIFtob3N0aW5nIGFuIEVwaWNlbnRlciBwcm9qZWN0IG9uIHlvdXIgb3duIHNlcnZlcl0oLi4vLi4vLi4vaG93X3RvL3NlbGZfaG9zdGluZy8pLlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogTmFtZSBvZiBjb2xsZWN0aW9uLiBEZWZhdWx0cyB0byBgL2AsIHRoYXQgaXMsIHRoZSByb290IGxldmVsIG9mIHlvdXIgcHJvamVjdCBhdCBgZm9yaW8uY29tL2FwcC95b3VyLWFjY291bnQtaWQveW91ci1wcm9qZWN0LWlkL2AuIFJlcXVpcmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcm9vdDogJy8nLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIG9wZXJhdGlvbnMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIGRvbWFpbjogJ2ZvcmlvLmNvbScsXG5cbiAgICAgICAgLy9PcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoa2V5LCByb290KSB7XG4gICAgICAgIGlmICghcm9vdCkge1xuICAgICAgICAgICAgcm9vdCA9IHNlcnZpY2VPcHRpb25zLnJvb3Q7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdkYXRhJykgKyBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKHJvb3QpO1xuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICB1cmwrPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBUaGUgbmFtZSBvZiB0aGUgZG9jdW1lbnQgdG8gc2VhcmNoLiBQYXNzIHRoZSBlbXB0eSBzdHJpbmcgKCcnKSB0byBzZWFyY2ggdGhlIGVudGlyZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHF1ZXJ5YCBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgdG8gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHtxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBrZXlgIElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWx1ZWAgKE9wdGlvbmFsKSBUaGUgZGF0YSB0byBzYXZlLiBJZiBga2V5YCBpcyBhIHN0cmluZywgdGhpcyBpcyB0aGUgdmFsdWUgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgdmFsdWUocykgdG8gc2F2ZSBhcmUgYWxyZWFkeSBwYXJ0IG9mIGBrZXlgIGFuZCB0aGlzIGFyZ3VtZW50IGlzIG5vdCByZXF1aXJlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhIG5hbWVkIGRvY3VtZW50IG9yIGVsZW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHNlcGFyYXRlbHkgaW4gY29uZmlndXJhdGlvbiBvcHRpb25zLCBlaXRoZXIgYXMgcGFydCBvZiB0aGUgY2FsbCBvciBhcyBwYXJ0IG9mIHRoZSBpbml0aWFsaXphdGlvbiBvZiBkcy5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYGtleWAgSWQgb2YgdGhlIGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYGtleWAgVGhlIGlkIG9mIHRoZSBkYXRhIHRvIHJldHVybi4gQ2FuIGJlIHRoZSBpZCBvZiBhIGRvY3VtZW50LCBvciBhIHBhdGggdG8gZGF0YSB3aXRoaW4gdGhhdCBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChrZXksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBkYXRhIGZyb20gY29sbGVjdGlvbi4gT25seSBkb2N1bWVudHMgKHRvcC1sZXZlbCBlbGVtZW50cyBpbiBlYWNoIGNvbGxlY3Rpb24pIGNhbiBiZSBkZWxldGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgZHMucmVtb3ZlKCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xBcnJheX0gYGtleXNgIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBwYXJhbXM7XG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KGtleXMpKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBpZDoga2V5cyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSAnJztcbiAgICAgICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5cywgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFcGljZW50ZXIgZG9lc24ndCBhbGxvdyBudWtpbmcgY29sbGVjdGlvbnNcbiAgICAgICAgLy8gICAgIC8qKlxuICAgICAgICAvLyAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgLy8gICAgICAqIEByZXR1cm4gbnVsbFxuICAgICAgICAvLyAgICAgICovXG4gICAgICAgIC8vICAgICBkZXN0cm95OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgnJywgb3B0aW9ucyk7XG4gICAgICAgIC8vICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyNNZW1iZXIgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgTWVtYmVyIEFQSSBBZGFwdGVyIHByb3ZpZGVzIG1ldGhvZHMgdG8gbG9vayB1cCBpbmZvcm1hdGlvbiBhYm91dCBlbmQgdXNlcnMgZm9yIHlvdXIgcHJvamVjdCBhbmQgaG93IHRoZXkgYXJlIGRpdmlkZWQgYWNyb3NzIGdyb3Vwcy4gSXQgaXMgYmFzZWQgb24gcXVlcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW01lbWJlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvbWVtYmVyLykuXG4gKlxuICogVGhpcyBpcyBvbmx5IG5lZWRlZCBmb3IgQXV0aGVudGljYXRlZCBwcm9qZWN0cywgdGhhdCBpcywgdGVhbSBwcm9qZWN0cyB3aXRoIFtlbmQgdXNlcnMgYW5kIGdyb3Vwc10oLi4vLi4vLi4vZ3JvdXBzX2FuZF9lbmRfdXNlcnMvKS4gRm9yIGV4YW1wbGUsIGlmIHNvbWUgb2YgeW91ciBlbmQgdXNlcnMgYXJlIGZhY2lsaXRhdG9ycywgb3IgaWYgeW91ciBlbmQgdXNlcnMgc2hvdWxkIGJlIHRyZWF0ZWQgZGlmZmVyZW50bHkgYmFzZWQgb24gd2hpY2ggZ3JvdXAgdGhleSBhcmUgaW4sIHVzZSB0aGUgTWVtYmVyIEFQSSB0byBmaW5kIHRoYXQgaW5mb3JtYXRpb24uXG4gKlxuICogICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gKiAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICdiNmIzMTNhMy1hYjg0LTQ3OWMtYmFlYS0yMDZmNmJmZjMzNycgfSk7XG4gKiAgICAgIG1hLmdldEdyb3VwRGV0YWlscyh7IGdyb3VwSWQ6ICcwMGI1MzMwOC05ODMzLTQ3ZjItYjIxZS0xMjc4YzA3ZDUzYjgnIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGFwaUVuZHBvaW50ID0gJ21lbWJlci9sb2NhbCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciB1c2VyIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBncm91cCBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuIE5vdGUgdGhhdCB0aGlzIGlzIHRoZSBncm91cCAqaWQqLCBub3QgdGhlIGdyb3VwICpuYW1lKi5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGdyb3VwSWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucywgc2VydmljZU9wdGlvbnMpO1xuXG4gICAgdmFyIGdldEZpbmFsUGFyYW1zID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBwYXRjaFVzZXJBY3RpdmVGaWVsZCA9IGZ1bmN0aW9uIChwYXJhbXMsIGFjdGl2ZSwgb3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBwYXJhbXMuZ3JvdXBJZCArICcvJyArIHBhcmFtcy51c2VySWRcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goeyBhY3RpdmU6IGFjdGl2ZSB9LCBodHRwT3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBhbGwgb2YgdGhlIGdyb3VwIG1lbWJlcnNoaXBzIGZvciBvbmUgZW5kIHVzZXIuIFRoZSBtZW1iZXJzaGlwIGRldGFpbHMgYXJlIHJldHVybmVkIGluIGFuIGFycmF5LCB3aXRoIG9uZSBlbGVtZW50IChncm91cCByZWNvcmQpIGZvciBlYWNoIGdyb3VwIHRvIHdoaWNoIHRoZSBlbmQgdXNlciBiZWxvbmdzLlxuICAgICAgICAqXG4gICAgICAgICogSW4gdGhlIG1lbWJlcnNoaXAgYXJyYXksIGVhY2ggZ3JvdXAgcmVjb3JkIGluY2x1ZGVzIHRoZSBncm91cCBpZCwgcHJvamVjdCBpZCwgYWNjb3VudCAodGVhbSkgaWQsIGFuZCBhbiBhcnJheSBvZiBtZW1iZXJzLiBIb3dldmVyLCBvbmx5IHRoZSB1c2VyIHdob3NlIHVzZXJJZCBpcyBpbmNsdWRlZCBpbiB0aGUgY2FsbCBpcyBsaXN0ZWQgaW4gdGhlIG1lbWJlcnMgYXJyYXkgKHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGVyZSBhcmUgb3RoZXIgbWVtYmVycyBpbiB0aGlzIGdyb3VwKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcignNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24obWVtYmVyc2hpcHMpe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPG1lbWJlcnNoaXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cobWVtYmVyc2hpcHNbaV0uZ3JvdXBJZCk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gYHBhcmFtc2AgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlci4gQWx0ZXJuYXRpdmVseSwgYW4gb2JqZWN0IHdpdGggZmllbGQgYHVzZXJJZGAgYW5kIHZhbHVlIHRoZSB1c2VyIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRHcm91cHNGb3JVc2VyOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB1c2VySWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ2V0UGFybXMgPSBpc1N0cmluZyA/IHsgdXNlcklkOiBwYXJhbXMgfSA6IF9waWNrKG9ialBhcmFtcywgJ3VzZXJJZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldFBhcm1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBvbmUgZ3JvdXAsIGluY2x1ZGluZyBhbiBhcnJheSBvZiBhbGwgaXRzIG1lbWJlcnMuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3VwRGV0YWlscygnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZ3JvdXApe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPGdyb3VwLm1lbWJlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhncm91cC5tZW1iZXJzW2ldLnVzZXJOYW1lKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIH1cbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoeyBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fSBgcGFyYW1zYCBUaGUgZ3JvdXAgaWQuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGBncm91cElkYCBhbmQgdmFsdWUgdGhlIGdyb3VwIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0R3JvdXBEZXRhaWxzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMuZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZ3JvdXBJZCBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBncm91cElkID0gaXNTdHJpbmcgPyBwYXJhbXMgOiBvYmpQYXJhbXMuZ3JvdXBJZDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIGdyb3VwSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgYWN0aXZlYC4gQWN0aXZlIGVuZCB1c2VycyBjYW4gYmUgYXNzaWduZWQgdG8gW3dvcmxkc10oLi4vd29ybGQtbWFuYWdlci8pIGluIG11bHRpcGxheWVyIGdhbWVzIGR1cmluZyBhdXRvbWF0aWMgYXNzaWdubWVudC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEubWFrZVVzZXJBY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIG1ha2VVc2VyQWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCB0cnVlLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBTZXQgYSBwYXJ0aWN1bGFyIGVuZCB1c2VyIGFzIGBpbmFjdGl2ZWAuIEluYWN0aXZlIGVuZCB1c2VycyBhcmUgbm90IGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VySW5hY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggdGhpcyBlbmQgdXNlciBiZWxvbmdzLCBhbmQgaW4gd2hpY2ggdGhlIGVuZCB1c2VyIHNob3VsZCBiZWNvbWUgaW5hY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckluYWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCBmYWxzZSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI1J1biBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBSdW4gQVBJIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBwZXJmb3JtIGNvbW1vbiB0YXNrcyBhcm91bmQgY3JlYXRpbmcgYW5kIHVwZGF0aW5nIHJ1bnMsIHZhcmlhYmxlcywgYW5kIGRhdGEuXG4gKlxuICogV2hlbiBidWlsZGluZyBpbnRlcmZhY2VzIHRvIHNob3cgcnVuIG9uZSBhdCBhIHRpbWUgKGFzIGZvciBzdGFuZGFyZCBlbmQgdXNlcnMpLCB0eXBpY2FsbHkgeW91IGZpcnN0IGluc3RhbnRpYXRlIGEgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGFuZCB0aGVuIGFjY2VzcyB0aGUgUnVuIFNlcnZpY2UgdGhhdCBpcyBhdXRvbWF0aWNhbGx5IHBhcnQgb2YgdGhlIG1hbmFnZXIsIHJhdGhlciB0aGFuIGluc3RhbnRpYXRpbmcgdGhlIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LiBUaGlzIGlzIGJlY2F1c2UgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLlxuICpcbiAqIEhvd2V2ZXIsIG1hbnkgb2YgdGhlIEVwaWNlbnRlciBzYW1wbGUgcHJvamVjdHMgdXNlIGEgUnVuIFNlcnZpY2UsIGJlY2F1c2UgZ2VuZXJhbGx5IHRoZSBzYW1wbGUgcHJvamVjdHMgYXJlIHBsYXllZCBpbiBvbmUgZW5kIHVzZXIgc2Vzc2lvbiBhbmQgZG9uJ3QgY2FyZSBhYm91dCBydW4gc3RhdGVzIG9yIFtydW4gc3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKS4gVGhlIFJ1biBBUEkgU2VydmljZSBpcyBhbHNvIHVzZWZ1bCBmb3IgYnVpbGRpbmcgYW4gaW50ZXJmYWNlIGZvciBhIGZhY2lsaXRhdG9yLCBiZWNhdXNlIGl0IG1ha2VzIGl0IGVhc3kgdG8gbGlzdCBkYXRhIGFjcm9zcyBtdWx0aXBsZSBydW5zICh1c2luZyB0aGUgYGZpbHRlcigpYCBhbmQgYHF1ZXJ5KClgIG1ldGhvZHMpLlxuICpcbiAqIFRvIHVzZSB0aGUgUnVuIEFQSSBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKlxuICogRm9yIGV4YW1wbGUsXG4gKlxuICogICAgICAgdmFyIHJzID0gbmV3IEYuc2VydmljZS5SdW4oe1xuICogICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgIH0pO1xuICogICAgICBycy5jcmVhdGUoJ3N1cHBseV9jaGFpbl9nYW1lLnB5JykudGhlbihmdW5jdGlvbihydW4pIHtcbiAqICAgICAgICAgICAgIHJzLmRvKCdzb21lT3BlcmF0aW9uJyk7XG4gKiAgICAgIH0pO1xuICpcbiAqXG4gKiBBZGRpdGlvbmFsbHksIGFsbCBBUEkgY2FsbHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFJ1biBBUEkgU2VydmljZSBkZWZhdWx0cyBsaXN0ZWQgYmVsb3cuXG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGBtb2RlbGAsIHRoZSBSdW4gU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKlxuICogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiAqICAgICAgICAgICBydW46IHtcbiAqICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseV9jaGFpbl9nYW1lLnB5JyxcbiAqICAgICAgICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICAgICAgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBybS5nZXRSdW4oKVxuICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBSdW4gU2VydmljZSxcbiAqICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4gKiAgICAgICAgICAgICAgIHZhciBycyA9IHJtLnJ1bjtcbiAqICAgICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgIH0pXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgVmFyaWFibGVzU2VydmljZSA9IHJlcXVpcmUoJy4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8IHN0b3JlLmdldCgnZXBpY2VudGVyLnRva2VuJykgfHwgJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgcnVucy4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlci5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRmxhZyBkZXRlcm1pbmVzIGlmIGBYLUF1dG9SZXN0b3JlOiB0cnVlYCBoZWFkZXIgaXMgc2VudCB0byBFcGljZW50ZXIuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBhdXRvUmVzdG9yZTogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuICAgIHVybENvbmZpZy5nZXRGaWx0ZXJVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJyk7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBxdXRpbC50b01hdHJpeEZvcm1hdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpO1xuXG4gICAgICAgIGlmIChmaWx0ZXIpIHtcbiAgICAgICAgICAgIHVybCArPSBmaWx0ZXIgKyAnLyc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmZpbHRlcjtcbiAgICAgICAgLy8gVGhlIHNlbWljb2xvbiBzZXBhcmF0ZWQgZmlsdGVyIGlzIHVzZWQgd2hlbiBmaWx0ZXIgaXMgYW4gb2JqZWN0XG4gICAgICAgIHZhciBpc0ZpbHRlclJ1bklkID0gZmlsdGVyICYmICQudHlwZShmaWx0ZXIpID09PSAnc3RyaW5nJztcbiAgICAgICAgaWYgKHNlcnZpY2VPcHRpb25zLmF1dG9SZXN0b3JlICYmIGlzRmlsdGVyUnVuSWQpIHtcbiAgICAgICAgICAgIC8vIEJ5IGRlZmF1bHQgYXV0b3JlcGxheSB0aGUgcnVuIGJ5IHNlbmRpbmcgdGhpcyBoZWFkZXIgdG8gZXBpY2VudGVyXG4gICAgICAgICAgICAvLyBodHRwczovL2ZvcmlvLmNvbS9lcGljZW50ZXIvZG9jcy9wdWJsaWMvcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNyZXRyaWV2aW5nXG4gICAgICAgICAgICB2YXIgYXV0b3Jlc3RvcmVPcHRzID0ge1xuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJ1gtQXV0b1Jlc3RvcmUnOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBhdXRvcmVzdG9yZU9wdHMsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgc2V0RmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBmaWx0ZXIgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgdXJsQ29uZmlnOiB1cmxDb25maWcsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyZWF0ZSBhIG5ldyBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIE5PVEU6IFR5cGljYWxseSB0aGlzIGlzIG5vdCB1c2VkISBVc2UgYFJ1bk1hbmFnZXIuZ2V0UnVuKClgIHdpdGggYSBgc3RyYXRlZ3lgIG9mIGBhbHdheXMtbmV3YCwgb3IgdXNlIGBSdW5NYW5hZ2VyLnJlc2V0KClgLiBTZWUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHJzLmNyZWF0ZSgnaGVsbG9fd29ybGQuamwnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYHBhcmFtc2AgSWYgYSBzdHJpbmcsIHRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IFttb2RlbCBmaWxlXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4gVGhpcyBpcyB0aGUgb25lIGZpbGUgaW4gdGhlIHByb2plY3QgdGhhdCBleHBsaWNpdGx5IGV4cG9zZXMgdmFyaWFibGVzIGFuZCBtZXRob2RzLCBhbmQgaXQgbXVzdCBiZSBzdG9yZWQgaW4gdGhlIE1vZGVsIGZvbGRlciBvZiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBJZiBhbiBvYmplY3QsIG1heSBpbmNsdWRlIGBtb2RlbGAsIGBzY29wZWAsIGFuZCBgZmlsZXNgLiAoU2VlIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bl9tYW5hZ2VyLykgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gYHNjb3BlYCBhbmQgYGZpbGVzYC4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICpcbiAgICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJykgfSk7XG4gICAgICAgICAgICB2YXIgcnVuQXBpUGFyYW1zID0gWydtb2RlbCcsICdzY29wZScsICdmaWxlcyddO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gdGhpcyBpcyBqdXN0IHRoZSBtb2RlbCBuYW1lXG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBtb2RlbDogcGFyYW1zIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHdoaXRlbGlzdCB0aGUgZmllbGRzIHRoYXQgd2UgYWN0dWFsbHkgY2FuIHNlbmQgdG8gdGhlIGFwaVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgcnVuQXBpUGFyYW1zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGVsZW1lbnRzIG9mIHRoZSBgcXNgIG9iamVjdCBhcmUgQU5EZWQgdG9nZXRoZXIgd2l0aGluIGEgc2luZ2xlIGNhbGwgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZXR1cm5zIHJ1bnMgd2l0aCBzYXZlZCA9IHRydWUgYW5kIHZhcmlhYmxlcy5wcmljZSA+IDEsXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgdmFyaWFibGVzLnByaWNlIGhhcyBiZWVuIHBlcnNpc3RlZCAocmVjb3JkZWQpXG4gICAgICAgICAqICAgICAgLy8gaW4gdGhlIG1vZGVsLlxuICAgICAgICAgKiAgICAgcnMucXVlcnkoe1xuICAgICAgICAgKiAgICAgICAgICAnc2F2ZWQnOiAndHJ1ZScsXG4gICAgICAgICAqICAgICAgICAgICcucHJpY2UnOiAnPjEnXG4gICAgICAgICAqICAgICAgIH0sXG4gICAgICAgICAqICAgICAgIHtcbiAgICAgICAgICogICAgICAgICAgc3RhcnRyZWNvcmQ6IDIsXG4gICAgICAgICAqICAgICAgICAgIGVuZHJlY29yZDogNVxuICAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBxc2AgUXVlcnkgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBRdWVyeWluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXMsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBxczsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFNpbWlsYXIgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJgIEZpbHRlciBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIEZpbHRlcmluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogZnVuY3Rpb24gKGZpbHRlciwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qoc2VydmljZU9wdGlvbnMuZmlsdGVyKSkge1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlcnZpY2VPcHRpb25zLmZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gZmlsdGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBkYXRhIGZvciBhIHNwZWNpZmljIHJ1bi4gVGhpcyBpbmNsdWRlcyBzdGFuZGFyZCBydW4gZGF0YSBzdWNoIGFzIHRoZSBhY2NvdW50LCBtb2RlbCwgcHJvamVjdCwgYW5kIGNyZWF0ZWQgYW5kIGxhc3QgbW9kaWZpZWQgZGF0ZXMuIFRvIHJlcXVlc3Qgc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLCBwYXNzIHRoZW0gYXMgcGFydCBvZiB0aGUgYGZpbHRlcnNgIHBhcmFtZXRlci5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IGlmIHRoZSBydW4gaXMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSksIGFueSBtb2RlbCB2YXJpYWJsZXMgYXJlIGF2YWlsYWJsZTsgaWYgdGhlIHJ1biBpcyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLCBvbmx5IG1vZGVsIHZhcmlhYmxlcyB0aGF0IGhhdmUgYmVlbiBwZXJzaXN0ZWQgJm1kYXNoOyB0aGF0IGlzLCBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwgJm1kYXNoOyBhcmUgYXZhaWxhYmxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgcnMubG9hZCgnYmI1ODk2NzctZDQ3Ni00OTcxLWE2OGUtMGM1OGQxOTFlNDUwJywgeyBpbmNsdWRlOiBbJy5wcmljZScsICcuc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBydW5JRGAgVGhlIHJ1biBpZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJzYCAoT3B0aW9uYWwpIE9iamVjdCBjb250YWluaW5nIGZpbHRlcnMgYW5kIG9wZXJhdGlvbiBtb2RpZmllcnMuIFVzZSBrZXkgYGluY2x1ZGVgIHRvIGxpc3QgbW9kZWwgdmFyaWFibGVzIHRoYXQgeW91IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUgcmVzcG9uc2UuIE90aGVyIGF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAocnVuSUQsIGZpbHRlcnMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmIChydW5JRCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJ1bklEOyAvL3Nob3VsZG4ndCBiZSBhYmxlIHRvIG92ZXItcmlkZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBhdHRyaWJ1dGVzIChkYXRhLCBtb2RlbCB2YXJpYWJsZXMpIG9mIHRoZSBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gYWRkICdjb21wbGV0ZWQnIGZpZWxkIHRvIHJ1biByZWNvcmRcbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBjb21wbGV0ZWQ6IHRydWUgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyB1cGRhdGUgJ3NhdmVkJyBmaWVsZCBvZiBydW4gcmVjb3JkLCBhbmQgdXBkYXRlIHZhbHVlcyBvZiBtb2RlbCB2YXJpYWJsZXMgZm9yIHRoaXMgcnVuXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgc2F2ZWQ6IHRydWUsIHZhcmlhYmxlczogeyBhOiAyMywgYjogMjMgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBhdHRyaWJ1dGVzYCBUaGUgcnVuIGRhdGEgYW5kIHZhcmlhYmxlcyB0byBzYXZlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGF0dHJpYnV0ZXMudmFyaWFibGVzYCBNb2RlbCB2YXJpYWJsZXMgbXVzdCBiZSBpbmNsdWRlZCBpbiBhIGB2YXJpYWJsZXNgIGZpZWxkIHdpdGhpbiB0aGUgYGF0dHJpYnV0ZXNgIG9iamVjdC4gKE90aGVyd2lzZSB0aGV5IGFyZSB0cmVhdGVkIGFzIHJ1biBkYXRhIGFuZCBhZGRlZCB0byB0aGUgcnVuIHJlY29yZCBkaXJlY3RseS4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uIChhdHRyaWJ1dGVzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKGF0dHJpYnV0ZXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBhIG1ldGhvZCBmcm9tIHRoZSBtb2RlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2QgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGBwYXJhbXNgIGFyZ3VtZW50IGlzIG5vcm1hbGx5IGFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byB0aGUgYG9wZXJhdGlvbmAuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXkuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCB5b3UgY2FuIGNvbWJpbmUgdGhlIGBvcGVyYXRpb25gIGFuZCBgcGFyYW1zYCBhcmd1bWVudHMgaW50byBhIHNpbmdsZSBvYmplY3QgaWYgeW91IHByZWZlciwgYXMgaW4gdGhlIGxhc3QgZXhhbXBsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic29sdmVcIiB0YWtlcyBubyBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLmRvKCdzb2x2ZScpO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsIFsnaGVsbG8nXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgJ2hlbGxvJyk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic3VtQXJyYXlcIiB0YWtlcyBvbmUgYXJndW1lbnQsIGFuIGFycmF5XG4gICAgICAgICAqICAgICBycy5kbygnc3VtQXJyYXknLCBbWzQsMiwxXV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImFkZFwiIHRha2VzIHR3byBhcmd1bWVudHMsIGJvdGggaW50ZWdlcnNcbiAgICAgICAgICogICAgIHJzLmRvKHsgbmFtZTonYWRkJywgcGFyYW1zOlsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYG9wZXJhdGlvbmAgTmFtZSBvZiBtZXRob2QuXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBwYXJhbXNgIChPcHRpb25hbCkgQW55IHBhcmFtZXRlcnMgdGhlIG9wZXJhdGlvbiB0YWtlcywgcGFzc2VkIGFzIGFuIGFycmF5LiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LCBhbmQgY2FuIGp1c3QgcGFzcyBpdCBkaXJlY3RseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZG86IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ2RvJywgb3BlcmF0aW9uLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wc0FyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnM7XG4gICAgICAgICAgICBpZiAob3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICAgICAgb3BzQXJncyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9uLCBvcHNBcmdzKTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgcG9zdE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcHJtcyA9IChyZXN1bHQuYXJnc1swXS5sZW5ndGggJiYgKHJlc3VsdC5hcmdzWzBdICE9PSBudWxsICYmIHJlc3VsdC5hcmdzWzBdICE9PSB1bmRlZmluZWQpKSA/IHJlc3VsdC5hcmdzWzBdIDogW107XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgYXJndW1lbnRzOiBwcm1zIH0sICQuZXh0ZW5kKHRydWUsIHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ29wZXJhdGlvbnMvJyArIHJlc3VsdC5vcHNbMF0gKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwsIHNlcXVlbnRpYWxseS5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2RzIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0aWFsaXplXCIgYW5kIFwic29sdmVcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWydpbml0aWFsaXplJywgJ3NvbHZlJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0XCIgYW5kIFwicmVzZXRcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncmVzZXQnLCBwYXJhbXM6IFsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJpbml0XCIgdGFrZXMgdHdvIGFyZ3VtZW50cyxcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJydW5tb2RlbFwiIHRha2VzIG5vbmVcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3J1bm1vZGVsJywgcGFyYW1zOiBbXSB9XSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBvcGVyYXRpb25zYCBJZiBub25lIG9mIHRoZSBtZXRob2RzIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgbWV0aG9kIG5hbWVzIChzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBtZXRob2RzIGRvIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGEgbWV0aG9kIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzZXJpYWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9TaW5nbGVPcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgb3AgPSBvcHMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICB2YXIgYXJnID0gYXJncy5zaGlmdCgpO1xuXG4gICAgICAgICAgICAgICAgbWUuZG8ob3AsIGFyZywge1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob3BzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbCwgZXhlY3V0aW5nIHRoZW0gaW4gcGFyYWxsZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kcyBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJzb2x2ZVwiIGFuZCBcInJlc2V0XCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWydzb2x2ZScsICdyZXNldCddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWyB7IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3N1YnRyYWN0JywgcGFyYW1zOlsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoeyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fSBgb3BlcmF0aW9uc2AgSWYgbm9uZSBvZiB0aGUgbWV0aG9kcyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG1ldGhvZCBuYW1lcyAoYXMgc3RyaW5ncykuIElmIGFueSBvZiB0aGUgbWV0aG9kcyBkbyB0YWtlIHBhcmFtZXRlcnMsIHlvdSBoYXZlIHR3byBvcHRpb25zLiBZb3UgY2FuIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhIG1ldGhvZCBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBwYXNzIGEgc2luZ2xlIG9iamVjdCB3aXRoIHRoZSBtZXRob2QgbmFtZSBhbmQgYSAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFsbGVsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG5cbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcXVldWUgID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaTwgb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcXVldWUucHVzaChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kbyhvcHNbaV0sIGFyZ3NbaV0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICQud2hlbi5hcHBseSh0aGlzLCBxdWV1ZSlcbiAgICAgICAgICAgICAgICAuZG9uZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2Vzcy5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvci5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY1N5bmNBUEkgPSB7XG4gICAgICAgIGdldEN1cnJlbnRDb25maWc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgfSxcbiAgICAgICAgLyoqXG4gICAgICAgICAgKiBSZXR1cm5zIGEgVmFyaWFibGVzIFNlcnZpY2UgaW5zdGFuY2UuIFVzZSB0aGUgdmFyaWFibGVzIGluc3RhbmNlIHRvIGxvYWQsIHNhdmUsIGFuZCBxdWVyeSBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLiBTZWUgdGhlIFtWYXJpYWJsZSBBUEkgU2VydmljZV0oLi4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAgICAgICAgKlxuICAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAgICAgIHZhciB2cyA9IHJzLnZhcmlhYmxlcygpO1xuICAgICAgICAgICogICAgICB2cy5zYXZlKHsgc2FtcGxlX2ludDogNCB9KTtcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBjb25maWdgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAgKi9cbiAgICAgICAgdmFyaWFibGVzOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgdnMgPSBuZXcgVmFyaWFibGVzU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZywge1xuICAgICAgICAgICAgICAgIHJ1blNlcnZpY2U6IHRoaXNcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIHJldHVybiB2cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljU3luY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4gKiAjI1N0YXRlIEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIFN0YXRlIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gcmVwbGF5IG9yIGNsb25lIHJ1bnMuIEl0IGJyaW5ncyBleGlzdGluZywgcGVyc2lzdGVkIHJ1biBkYXRhIGZyb20gdGhlIGRhdGFiYXNlIGJhY2sgaW50byBtZW1vcnksIHVzaW5nIHRoZSBzYW1lIHJ1biBpZCAoYHJlcGxheWApIG9yIGEgbmV3IHJ1biBpZCAoYGNsb25lYCkuIFJ1bnMgbXVzdCBiZSBpbiBtZW1vcnkgaW4gb3JkZXIgZm9yIHlvdSB0byB1cGRhdGUgdmFyaWFibGVzIG9yIGNhbGwgb3BlcmF0aW9ucyBvbiB0aGVtLlxuICpcbiAqIFNwZWNpZmljYWxseSwgdGhlIFN0YXRlIEFQSSBBZGFwdGVyIHdvcmtzIGJ5IFwicmUtcnVubmluZ1wiIHRoZSBydW4gKHVzZXIgaW50ZXJhY3Rpb25zKSBmcm9tIHRoZSBjcmVhdGlvbiBvZiB0aGUgcnVuIHVwIHRvIHRoZSB0aW1lIGl0IHdhcyBsYXN0IHBlcnNpc3RlZCBpbiB0aGUgZGF0YWJhc2UuIFRoaXMgcHJvY2VzcyB1c2VzIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIHJ1bidzIG1vZGVsLiBUaGVyZWZvcmUsIGlmIHRoZSBtb2RlbCBoYXMgY2hhbmdlZCBzaW5jZSB0aGUgb3JpZ2luYWwgcnVuIHdhcyBjcmVhdGVkLCB0aGUgcmV0cmlldmVkIHJ1biB3aWxsIHVzZSB0aGUgbmV3IG1vZGVsIOKAlCBhbmQgbWF5IGVuZCB1cCBoYXZpbmcgZGlmZmVyZW50IHZhbHVlcyBvciBiZWhhdmlvciBhcyBhIHJlc3VsdC4gVXNlIHdpdGggY2FyZSFcbiAqXG4gKiBUbyB1c2UgdGhlIFN0YXRlIEFQSSBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBjYWxsIGl0cyBtZXRob2RzOlxuICpcbiAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJ30pO1xuICpcbiAqIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgcHJvamVjdGAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4gKlxuICovXG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBhcGlFbmRwb2ludCA9ICdtb2RlbC9zdGF0ZSc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgfTtcblxuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcbiAgICB2YXIgcGFyc2VSdW5JZE9yRXJyb3IgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSAmJiBwYXJhbXMucnVuSWQpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbXMucnVuSWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwYXNzIGluIGEgcnVuIGlkJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGF5IGEgcnVuLiBBZnRlciB0aGlzIGNhbGwsIHRoZSBydW4sIHdpdGggaXRzIG9yaWdpbmFsIHJ1biBpZCwgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gKEl0IGNvbnRpbnVlcyB0byBiZSBwZXJzaXN0ZWQgaW50byB0aGUgRXBpY2VudGVyIGRhdGFiYXNlIGF0IHJlZ3VsYXIgaW50ZXJ2YWxzLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJywgc3RvcEJlZm9yZTogJ2NhbGN1bGF0ZVNjb3JlJ30pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBicmluZyBiYWNrIHRvIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBgcGFyYW1zLmV4Y2x1ZGVgIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZXBsYXk6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdyZXBsYXknIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ2xvbmUgYSBnaXZlbiBydW4gYW5kIHJldHVybiBhIG5ldyBydW4gaW4gdGhlIHNhbWUgc3RhdGUgYXMgdGhlIGdpdmVuIHJ1bi5cbiAgICAgICAgKlxuICAgICAgICAqIFRoZSBuZXcgcnVuIGlkIGlzIG5vdyBhdmFpbGFibGUgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIFRoZSBuZXcgcnVuIGluY2x1ZGVzIGEgY29weSBvZiBhbGwgb2YgdGhlIGRhdGEgZnJvbSB0aGUgb3JpZ2luYWwgcnVuLCBFWENFUFQ6XG4gICAgICAgICpcbiAgICAgICAgKiAqIFRoZSBgc2F2ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAuXG4gICAgICAgICogKiBUaGUgYGluaXRpYWxpemVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgbm90IGNvcGllZCBmcm9tIHRoZSBvcmlnaW5hbCBydW4gcmVjb3JkLiBJdCBkZWZhdWx0cyB0byBgZmFsc2VgIGJ1dCBtYXkgY2hhbmdlIHRvIGB0cnVlYCBhcyB0aGUgbmV3IHJ1biBpcyBhZHZhbmNlZC4gRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGhhcyBiZWVuIGEgY2FsbCB0byB0aGUgYHN0ZXBgIGZ1bmN0aW9uIChmb3IgVmVuc2ltIG1vZGVscyksIHRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGlzIHNldCB0byBgdHJ1ZWAuXG4gICAgICAgICogKiBUaGUgYGNyZWF0ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyB0aGUgZGF0ZSBhbmQgdGltZSBhdCB3aGljaCB0aGUgY2xvbmUgd2FzIGNyZWF0ZWQgKG5vdCB0aGUgdGltZSB0aGF0IHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQuKVxuICAgICAgICAqXG4gICAgICAgICogVGhlIG9yaWdpbmFsIHJ1biByZW1haW5zIG9ubHkgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLWRiKS5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5jbG9uZSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnLCBleGNsdWRlOiBbJ2ludGVyaW1DYWxjdWxhdGlvbiddIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBjbG9uZSBmcm9tIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBuZXdseSBjbG9uZWQgcnVuIGlzIGFkdmFuY2VkIG9ubHkgdXAgdG8gdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgdGhpcyBtZXRob2QuXG4gICAgICAgICogQHBhcmFtIHthcnJheX0gYHBhcmFtcy5leGNsdWRlYCAoT3B0aW9uYWwpIEFycmF5IG9mIG1ldGhvZHMgdG8gZXhjbHVkZSB3aGVuIGFkdmFuY2luZyB0aGUgbmV3bHkgY2xvbmVkIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGNsb25lOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcnVuSWQgPSBwYXJzZVJ1bklkT3JFcnJvcihwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgcmVwbGF5T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHJ1bklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgYWN0aW9uOiAnY2xvbmUnIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBlcGlWZXJzaW9uID0gcmVxdWlyZSgnLi4vYXBpLXZlcnNpb24uanNvbicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IHVybHV0aWxzIHRvIGdldCBob3N0LCBzaW5jZSBubyB3aW5kb3cgb24gbm9kZVxuXG4gICAgdmFyIEFQSV9QUk9UT0NPTCA9ICdodHRwcyc7XG4gICAgdmFyIEhPU1RfQVBJX01BUFBJTkcgPSB7XG4gICAgICAgICdmb3Jpby5jb20nOiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICdmb3Jpb2Rldi5jb20nOiAnYXBpLmVwaWNlbnRlci5mb3Jpb2Rldi5jb20nXG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNFeHBvcnRzID0ge1xuICAgICAgICBwcm90b2NvbDogQVBJX1BST1RPQ09MLFxuXG4gICAgICAgIGFwaTogJycsXG5cbiAgICAgICAgaG9zdDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICBpZiAoIWhvc3QgfHwgaG9zdC5pbmRleE9mKCdsb2NhbCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGhvc3QgPSAnZm9yaW8uY29tJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAoSE9TVF9BUElfTUFQUElOR1tob3N0XSkgPyBIT1NUX0FQSV9NQVBQSU5HW2hvc3RdIDogJ2FwaS4nICsgaG9zdDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBhcHBQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gcGF0aCAmJiBwYXRoWzFdIHx8ICcnO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFjY291bnRQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFjY250ID0gJyc7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIGFjY250ID0gcGF0aFsyXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhY2NudDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBwcm9qZWN0UGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwcmogPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIGlmIChwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnKSB7XG4gICAgICAgICAgICAgICAgcHJqID0gcGF0aFszXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBwcmo7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgdmVyc2lvblBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgdmVyc2lvbiA9IGVwaVZlcnNpb24udmVyc2lvbiA/IGVwaVZlcnNpb24udmVyc2lvbiArICcvJyA6ICcnO1xuICAgICAgICAgICAgcmV0dXJuIHZlcnNpb247XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgaXNMb2NhbGhvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICByZXR1cm4gKCFob3N0IHx8IGhvc3QuaW5kZXhPZignbG9jYWwnKSAhPT0gLTEpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGdldEFQSVBhdGg6IGZ1bmN0aW9uIChhcGkpIHtcbiAgICAgICAgICAgIHZhciBQUk9KRUNUX0FQSVMgPSBbJ3J1bicsICdkYXRhJywgJ2ZpbGUnXTtcblxuICAgICAgICAgICAgdmFyIGFwaVBhdGggPSB0aGlzLnByb3RvY29sICsgJzovLycgKyB0aGlzLmhvc3QgKyAnLycgKyB0aGlzLnZlcnNpb25QYXRoICsgYXBpICsgJy8nO1xuXG4gICAgICAgICAgICBpZiAoJC5pbkFycmF5KGFwaSwgUFJPSkVDVF9BUElTKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBhcGlQYXRoICs9IHRoaXMuYWNjb3VudFBhdGggKyAnLycgKyB0aGlzLnByb2plY3RQYXRoICArICcvJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhcGlQYXRoO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHB1YmxpY0V4cG9ydHMsIGNvbmZpZyk7XG4gICAgcmV0dXJuIHB1YmxpY0V4cG9ydHM7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4qICMjVXNlciBBUEkgQWRhcHRlclxuKlxuKiBUaGUgVXNlciBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHJldHJpZXZlIGRldGFpbHMgYWJvdXQgZW5kIHVzZXJzIGluIHlvdXIgdGVhbSAoYWNjb3VudCkuIEl0IGlzIGJhc2VkIG9uIHRoZSBxdWVyeWluZyBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbVXNlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvdXNlci8pLlxuKlxuKiBUbyB1c2UgdGhlIFVzZXIgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHMuXG4qXG4qICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nXG4qICAgICAgIH0pO1xuKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiogICAgICAgdWEuZ2V0KHsgdXNlck5hbWU6ICdqc21pdGgnIH0pO1xuKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4qXG4qIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgdG9rZW5gIGlmIHRoZXkgYXJlIG5vdCBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgY3VycmVudCBjb250ZXh0LlxuKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2Nlc3MgdG9rZW4gdG8gdXNlIHdoZW4gc2VhcmNoaW5nIGZvciBlbmQgdXNlcnMuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgcGFydGljdWxhciBlbmQgdXNlcnMgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIG5hbWUgb3IgdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4gICAgICAgICogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgZmlsdGVyYCBPYmplY3Qgd2l0aCBmaWVsZCBgdXNlck5hbWVgIGFuZCB2YWx1ZSBvZiB0aGUgdXNlcm5hbWUuIEFsdGVybmF0aXZlbHksIG9iamVjdCB3aXRoIGZpZWxkIGBpZGAgYW5kIHZhbHVlIG9mIGFuIGFycmF5IG9mIHVzZXIgaWRzLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWx0ZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciB0b1FGaWx0ZXIgPSBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgLy8gQVBJIG9ubHkgc3VwcG9ydHMgZmlsdGVyaW5nIGJ5IHVzZXJuYW1lIGZvciBub3dcbiAgICAgICAgICAgICAgICBpZiAoZmlsdGVyLnVzZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5xID0gZmlsdGVyLnVzZXJOYW1lO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgdG9JZEZpbHRlcnMgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZCA9ICQuaXNBcnJheShpZCkgPyBpZCA6IFtpZF07XG4gICAgICAgICAgICAgICAgcmV0dXJuICdpZD0nICsgaWQuam9pbignJmlkPScpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIGdldEZpbHRlcnMgPSBbXG4gICAgICAgICAgICAgICAgJ2FjY291bnQ9JyArIGdldE9wdGlvbnMuYWNjb3VudCxcbiAgICAgICAgICAgICAgICB0b0lkRmlsdGVycyhmaWx0ZXIuaWQpLFxuICAgICAgICAgICAgICAgIHF1dGlsLnRvUXVlcnlGb3JtYXQodG9RRmlsdGVyKGZpbHRlcikpXG4gICAgICAgICAgICBdLmpvaW4oJyYnKTtcblxuICAgICAgICAgICAgLy8gc3BlY2lhbCBjYXNlIGZvciBxdWVyaWVzIHdpdGggbGFyZ2UgbnVtYmVyIG9mIGlkc1xuICAgICAgICAgICAgLy8gbWFrZSBpdCBhcyBhIHBvc3Qgd2l0aCBHRVQgc2VtYW50aWNzXG4gICAgICAgICAgICB2YXIgdGhyZXNob2xkID0gMzA7XG4gICAgICAgICAgICBpZiAoZmlsdGVyLmlkICYmICQuaXNBcnJheShmaWx0ZXIuaWQpICYmIGZpbHRlci5pZC5sZW5ndGggPj0gdGhyZXNob2xkKSB7XG4gICAgICAgICAgICAgICAgZ2V0T3B0aW9ucy51cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpICsgJz9fbWV0aG9kPUdFVCc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGlkOiBmaWx0ZXIuaWQgfSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRGaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGEgc2luZ2xlIGVuZCB1c2VyIGluIHlvdXIgdGVhbSwgYmFzZWQgb24gdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRCeUlkOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcHVibGljQVBJLmdldCh7IGlkOiB1c2VySWQgfSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG5cblxuXG5cbiIsIi8qKlxuICpcbiAqICMjVmFyaWFibGVzIEFQSSBTZXJ2aWNlXG4gKlxuICogVXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSB0byByZWFkLCB3cml0ZSwgYW5kIHNlYXJjaCBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLlxuICpcbiAqICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJ1xuICogICAgICAgICAgIH1cbiAqICAgICAgfSk7XG4gKiAgICAgcm0uZ2V0UnVuKClcbiAqICAgICAgIC50aGVuKGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgdmFyIHZzID0gcm0ucnVuLnZhcmlhYmxlcygpO1xuICogICAgICAgICAgdnMuc2F2ZSh7c2FtcGxlX2ludDogNH0pO1xuICogICAgICAgIH0pO1xuICpcbiAqL1xuXG5cbiAndXNlIHN0cmljdCc7XG5cbiB2YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG4gdmFyIHJ1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9ydW4tdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcnVucyBvYmplY3QgdG8gd2hpY2ggdGhlIHZhcmlhYmxlIGZpbHRlcnMgYXBwbHkuIERlZmF1bHRzIHRvIG51bGwuXG4gICAgICAgICAqIEB0eXBlIHtydW5TZXJ2aWNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcnVuU2VydmljZTogbnVsbFxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ3ZhcmlhYmxlcy8nO1xuICAgIH07XG5cbiAgICB2YXIgYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9IHtcbiAgICAgICAgdXJsOiBnZXRVUkxcbiAgICB9O1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICBodHRwLnNwbGl0R2V0ID0gcnV0aWwuc3BsaXRHZXRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB2YWx1ZXMgZm9yIGEgdmFyaWFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMubG9hZCgnc2FtcGxlX2ludCcpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCl7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgY29udGFpbnMgdGhlIHZhbHVlIG9mIHNhbXBsZV9pbnRcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgdmFyaWFibGVgIE5hbWUgb2YgdmFyaWFibGUgdG8gbG9hZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHZhcmlhYmxlLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG91dHB1dE1vZGlmaWVyLCAkLmV4dGVuZCh7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IGdldFVSTCgpICsgdmFyaWFibGUgKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHZhcmlhYmxlcywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxdWVyeWAgb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KFsncHJpY2UnLCAnc2FsZXMnXSlcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgaXMgYW4gb2JqZWN0IHdpdGggdGhlIHZhbHVlcyBvZiB0aGUgcmVxdWVzdGVkIHZhcmlhYmxlczogdmFsLnByaWNlLCB2YWwuc2FsZXNcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoeyBpbmNsdWRlOlsncHJpY2UnLCAnc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IGBxdWVyeWAgVGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgcmVxdWVzdGVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9RdWVyeSBhbmQgb3V0cHV0TW9kaWZpZXIgYXJlIGJvdGggcXVlcnlzdHJpbmdzIGluIHRoZSB1cmw7IG9ubHkgY2FsbGluZyB0aGVtIG91dCBzZXBhcmF0ZWx5IGhlcmUgdG8gYmUgY29uc2lzdGVudCB3aXRoIHRoZSBvdGhlciBjYWxsc1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KHF1ZXJ5KSkge1xuICAgICAgICAgICAgICAgIHF1ZXJ5ID0geyBpbmNsdWRlOiBxdWVyeSB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJC5leHRlbmQocXVlcnksIG91dHB1dE1vZGlmaWVyKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KHF1ZXJ5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgdmFsdWVzIHRvIG1vZGVsIHZhcmlhYmxlcy4gT3ZlcndyaXRlcyBleGlzdGluZyB2YWx1ZXMuIE5vdGUgdGhhdCB5b3UgY2FuIG9ubHkgdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoQW4gYWx0ZXJuYXRlIHdheSB0byB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlzIHRvIGNhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwgYW5kIG1ha2Ugc3VyZSB0aGF0IHRoZSBtZXRob2QgcGVyc2lzdHMgdGhlIHZhcmlhYmxlcy4gU2VlIGBkb2AsIGBzZXJpYWxgLCBhbmQgYHBhcmFsbGVsYCBpbiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgZm9yIGNhbGxpbmcgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMuc2F2ZSgncHJpY2UnLCA0KTtcbiAgICAgICAgICogICAgICB2cy5zYXZlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgdmFyaWFibGVgIEFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgbW9kZWwgdmFyaWFibGVzIGFuZCB0aGUgdmFsdWVzIHRvIHNhdmUuIEFsdGVybmF0aXZlbHksIGEgc3RyaW5nIHdpdGggdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbGAgKE9wdGlvbmFsKSBJZiBwYXNzaW5nIGEgc3RyaW5nIGZvciBgdmFyaWFibGVgLCB1c2UgdGhpcyBhcmd1bWVudCBmb3IgdGhlIHZhbHVlIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uICh2YXJpYWJsZSwgdmFsLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW3ZhcmlhYmxlXSA9IHZhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoLmNhbGwodGhpcywgYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdCBBdmFpbGFibGUgdW50aWwgdW5kZXJseWluZyBBUEkgc3VwcG9ydHMgUFVULiBPdGhlcndpc2Ugc2F2ZSB3b3VsZCBiZSBQVVQgYW5kIG1lcmdlIHdvdWxkIGJlIFBBVENIXG4gICAgICAgIC8vICpcbiAgICAgICAgLy8gICogU2F2ZSB2YWx1ZXMgdG8gdGhlIGFwaS4gTWVyZ2VzIGFycmF5cywgYnV0IG90aGVyd2lzZSBzYW1lIGFzIHNhdmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSB2YXJpYWJsZSBPYmplY3Qgd2l0aCBhdHRyaWJ1dGVzLCBvciBzdHJpbmcga2V5XG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSB2YWwgT3B0aW9uYWwgaWYgcHJldiBwYXJhbWV0ZXIgd2FzIGEgc3RyaW5nLCBzZXQgdmFsdWUgaGVyZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAZXhhbXBsZVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSgncHJpY2UnLCA0KTtcblxuICAgICAgICAvLyBtZXJnZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgLy8gICAgIHZhciBhdHRycztcbiAgICAgICAgLy8gICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIC8vICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgIC8vICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAvLyAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAvLyAgICAgfVxuICAgICAgICAvLyAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAvLyAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICAvLyB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNXb3JsZCBBUEkgQWRhcHRlclxuICpcbiAqIEEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsIC0tIGluY2x1ZGluZyBzZXR0aW5nIHZhcmlhYmxlcywgbWFraW5nIGRlY2lzaW9ucywgYW5kIGNhbGxpbmcgb3BlcmF0aW9ucy4gRm9yIGJ1aWxkaW5nIG11bHRpcGxheWVyIHNpbXVsYXRpb25zIHlvdSB0eXBpY2FsbHkgd2FudCBtdWx0aXBsZSBlbmQgdXNlcnMgdG8gc2hhcmUgdGhlIHNhbWUgc2V0IG9mIGludGVyYWN0aW9ucywgYW5kIHdvcmsgd2l0aGluIGEgY29tbW9uIHN0YXRlLiBFcGljZW50ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUgXCJ3b3JsZHNcIiB0byBoYW5kbGUgc3VjaCBjYXNlcy4gT25seSBbdGVhbSBwcm9qZWN0c10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIGNhbiBiZSBtdWx0aXBsYXllci5cbiAqXG4gKiBUaGUgV29ybGQgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUsIGFjY2VzcywgYW5kIG1hbmlwdWxhdGUgbXVsdGlwbGF5ZXIgd29ybGRzIHdpdGhpbiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBZb3UgY2FuIHVzZSB0aGlzIHRvIGFkZCBhbmQgcmVtb3ZlIGVuZCB1c2VycyBmcm9tIHRoZSB3b3JsZCwgYW5kIHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgcmVtb3ZlIHRoZWlyIHJ1bnMuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4gKFRoZSByZWxhdGVkIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyLykgcHJvdmlkZXMgYW4gZWFzeSB3YXkgdG8gYWNjZXNzIHJ1bnMgYW5kIHdvcmxkcyBmb3IgcGFydGljdWxhciBlbmQgdXNlcnMsIHNvIGlzIHR5cGljYWxseSB1c2VkIGluIHBhZ2VzIHRoYXQgZW5kIHVzZXJzIHdpbGwgaW50ZXJhY3Qgd2l0aC4pXG4gKlxuICogQXMgd2l0aCBhbGwgdGhlIG90aGVyIFtBUEkgQWRhcHRlcnNdKC4uLy4uLyksIGFsbCBtZXRob2RzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBXb3JsZCBBUEkgU2VydmljZSBkZWZhdWx0cy5cbiAqXG4gKiBUbyB1c2UgdGhlIFdvcmxkIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSksIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKSwgYW5kIGdyb3VwICgqKkdyb3VwIE5hbWUqKikuXG4gKlxuICogICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gKiAgICAgICB3YS5jcmVhdGUoKVxuICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAqICAgICAgICAgICAgICAvLyBjYWxsIG1ldGhvZHMsIGUuZy4gd2EuYWRkVXNlcnMoKVxuICogICAgICAgICAgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG4vLyB2YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGFwaUJhc2UgPSAnbXVsdGlwbGF5ZXIvJztcbnZhciBhc3NpZ25tZW50RW5kcG9pbnQgPSBhcGlCYXNlICsgJ2Fzc2lnbic7XG52YXIgYXBpRW5kcG9pbnQgPSBhcGlCYXNlICsgJ3dvcmxkJztcbnZhciBwcm9qZWN0RW5kcG9pbnQgPSBhcGlCYXNlICsgJ3Byb2plY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkoeyBzeW5jaHJvbm91czogdHJ1ZSB9KTtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgZ3JvdXA6IHVuZGVmaW5lZCxcblxuICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIHJ1bnMgaW4gdGhpcyB3b3JsZC4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbW9kZWw6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JpdGVyaWEgYnkgd2hpY2ggdG8gZmlsdGVyIHdvcmxkLiBDdXJyZW50bHkgb25seSBzdXBwb3J0cyB3b3JsZC1pZHMgYXMgZmlsdGVycy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlbmllbmNlIGFsaWFzIGZvciBmaWx0ZXJcbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3BcbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMucHJvamVjdCA9IHVybENvbmZpZy5wcm9qZWN0UGF0aDtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBzZXRJZEZpbHRlck9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmlkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gd29ybGQgaWQgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdC4gVGhpcyBjb3VsZCBoYXBwZW4gaWYgdGhlIHVzZXIgaXMgbm90IGFzc2lnbmVkIHRvIGEgd29ybGQgYW5kIGlzIHRyeWluZyB0byB3b3JrIHdpdGggcnVucyBmcm9tIHRoYXQgd29ybGQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAoIW9wdGlvbnMubW9kZWwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gbW9kZWwgc3BlY2lmaWVkIHRvIGdldCB0aGUgY3VycmVudCBydW4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENyZWF0ZXMgYSBuZXcgV29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBVc2luZyB0aGlzIG1ldGhvZCBpcyByYXJlLiBJdCBpcyBtb3JlIGNvbW1vbiB0byBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkgd2hpbGUgeW91IGBhdXRvQXNzaWduKClgIGVuZCB1c2VycyB0byB3b3JsZHMuIChJbiB0aGlzIGNhc2UsIGNvbmZpZ3VyYXRpb24gZGF0YSBmb3IgdGhlIHdvcmxkLCBzdWNoIGFzIHRoZSByb2xlcywgYXJlIHJlYWQgZnJvbSB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9uLCBmb3IgZXhhbXBsZSBieSBgZ2V0UHJvamVjdFNldHRpbmdzKClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSh7XG4gICAgICAgICogICAgICAgICAgIHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddXG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBjcmVhdGUgdGhlIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwYCAoT3B0aW9uYWwpIFRoZSAqKkdyb3VwIE5hbWUqKiB0byBjcmVhdGUgdGhpcyB3b3JsZCB1bmRlci4gT25seSBlbmQgdXNlcnMgaW4gdGhpcyBncm91cCBhcmUgZWxpZ2libGUgdG8gam9pbiB0aGUgd29ybGQuIE9wdGlvbmFsIGhlcmU7IHJlcXVpcmVkIHdoZW4gaW5zdGFudGlhdGluZyB0aGUgc2VydmljZSAoYG5ldyBGLnNlcnZpY2UuV29ybGQoKWApLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfSk7XG4gICAgICAgICAgICB2YXIgd29ybGRBcGlQYXJhbXMgPSBbJ3Njb3BlJywgJ2ZpbGVzJywgJ3JvbGVzJywgJ29wdGlvbmFsUm9sZXMnLCAnbWluVXNlcnMnLCAnZ3JvdXAnLCAnbmFtZSddO1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHdvcmxkQXBpUGFyYW1zKTtcblxuICAgICAgICAgICAgLy8gYWNjb3VudCBhbmQgcHJvamVjdCBnbyBpbiB0aGUgYm9keSwgbm90IGluIHRoZSB1cmxcbiAgICAgICAgICAgICQuZXh0ZW5kKHBhcmFtcywgX3BpY2soc2VydmljZU9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pKTtcblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBVcGRhdGVzIGEgV29ybGQsIGZvciBleGFtcGxlIHRvIHJlcGxhY2UgdGhlIHJvbGVzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgeW91IGNvbXBsZXRlIHdvcmxkIGNvbmZpZ3VyYXRpb24gYXQgdGhlIHByb2plY3QgbGV2ZWwsIHJhdGhlciB0aGFuIGF0IHRoZSB3b3JsZCBsZXZlbC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguIEhvd2V2ZXIsIHRoaXMgbWV0aG9kIGlzIGF2YWlsYWJsZSBpZiB5b3UgbmVlZCB0byB1cGRhdGUgdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBwYXJ0aWN1bGFyIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnVwZGF0ZSh7IHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHVwZGF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMubmFtZWAgQSBzdHJpbmcgaWRlbnRpZmllciBmb3IgdGhlIGxpbmtlZCBlbmQgdXNlcnMsIGZvciBleGFtcGxlLCBcIm5hbWVcIjogXCJPdXIgVGVhbVwiLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHdoaXRlbGlzdCA9IFsncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycyddO1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHVwZGF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zIHx8IHt9LCB3aGl0ZWxpc3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChwYXJhbXMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYW4gZXhpc3Rpbmcgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBUaGlzIGZ1bmN0aW9uIG9wdGlvbmFsbHkgdGFrZXMgb25lIGFyZ3VtZW50LiBJZiB0aGUgYXJndW1lbnQgaXMgYSBzdHJpbmcsIGl0IGlzIHRoZSBpZCBvZiB0aGUgd29ybGQgdG8gZGVsZXRlLiBJZiB0aGUgYXJndW1lbnQgaXMgYW4gb2JqZWN0LCBpdCBpcyB0aGUgb3ZlcnJpZGUgZm9yIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmRlbGV0ZSgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUsIG9yIG9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAob3B0aW9ucyAmJiAodHlwZW9mIG9wdGlvbnMgPT09ICdzdHJpbmcnKSkgPyB7IGZpbHRlcjogb3B0aW9ucyB9IDoge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRlbGV0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGRlbGV0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBjdXJyZW50IGluc3RhbmNlIG9mIHRoZSBXb3JsZCBBUEkgQWRhcHRlciAoaW5jbHVkaW5nIGFsbCBzdWJzZXF1ZW50IGZ1bmN0aW9uIGNhbGxzLCB1bnRpbCB0aGUgY29uZmlndXJhdGlvbiBpcyB1cGRhdGVkIGFnYWluKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoey4uLn0pLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogJzEyMycgfSkuYWRkVXNlcih7IHVzZXJJZDogJzEyMycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgY29uZmlnYCBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gdXNlIGluIHVwZGF0aW5nIGV4aXN0aW5nIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZUNvbmZpZzogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMsIGNvbmZpZyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIExpc3RzIGFsbCB3b3JsZHMgZm9yIGEgZ2l2ZW4gYWNjb3VudCwgcHJvamVjdCwgYW5kIGdyb3VwLiBBbGwgdGhyZWUgYXJlIHJlcXVpcmVkLCBhbmQgaWYgbm90IHNwZWNpZmllZCBhcyBwYXJhbWV0ZXJzLCBhcmUgcmVhZCBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJ0ZWFtMVwiXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5saXN0KCk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJvdGhlci1ncm91cC1uYW1lXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoeyBncm91cDogJ290aGVyLWdyb3VwLW5hbWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBsaXN0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGFsbCB3b3JsZHMgdGhhdCBhbiBlbmQgdXNlciBiZWxvbmdzIHRvIGZvciBhIGdpdmVuIGFjY291bnQgKHRlYW0pLCBwcm9qZWN0LCBhbmQgZ3JvdXAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZ2V0V29ybGRzRm9yVXNlcignYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJylcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZHMgYXJlIGJlaW5nIHJldHJpZXZlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldFdvcmxkc0ZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YXIgZmlsdGVycyA9ICQuZXh0ZW5kKFxuICAgICAgICAgICAgICAgIF9waWNrKGdldE9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pLFxuICAgICAgICAgICAgICAgIHsgdXNlcklkOiB1c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGluZm9ybWF0aW9uIGZvciBhIHNwZWNpZmljIHdvcmxkLiBBbGwgZnVydGhlciBjYWxscyB0byB0aGUgd29ybGQgc2VydmljZSB3aWxsIHVzZSB0aGUgaWQgcHJvdmlkZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgd29ybGRJZGAgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBsb2FkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgd29ybGRpZCB0byBsb2FkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy8nIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQWRkcyBhbiBlbmQgdXNlciBvciBsaXN0IG9mIGVuZCB1c2VycyB0byBhIGdpdmVuIHdvcmxkLiBUaGUgZW5kIHVzZXIgbXVzdCBiZSBhIG1lbWJlciBvZiB0aGUgYGdyb3VwYCB0aGF0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlclxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoWydiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2Vycyh7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdWUCBTYWxlcycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBzZXZlcmFsIHVzZXJzXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgeyB1c2VySWQ6ICdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ1ZQIE1hcmtldGluZycgfSxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgRW5naW5lZXJpbmcnIH1cbiAgICAgICAgKiAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgICAgICAvLyBhZGQgb25lIHVzZXIgdG8gYSBzcGVjaWZpYyB3b3JsZFxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB7IGZpbHRlcjogd29ybGQuaWQgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdHxhcnJheX0gYHVzZXJzYCBVc2VyIGlkLCBhcnJheSBvZiB1c2VyIGlkcywgb2JqZWN0LCBvciBhcnJheSBvZiBvYmplY3RzIG9mIHRoZSB1c2VycyB0byBhZGQgdG8gdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJzLnJvbGVgIFRoZSBgcm9sZWAgdGhlIHVzZXIgc2hvdWxkIGhhdmUgaW4gdGhlIHdvcmxkLiBJdCBpcyB1cCB0byB0aGUgY2FsbGVyIHRvIGVuc3VyZSwgaWYgbmVlZGVkLCB0aGF0IHRoZSBgcm9sZWAgcGFzc2VkIGluIGlzIG9uZSBvZiB0aGUgYHJvbGVzYCBvciBgb3B0aW9uYWxSb2xlc2Agb2YgdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSB3b3JsZCB0byB3aGljaCB0aGUgdXNlcnMgc2hvdWxkIGJlIGFkZGVkLiBJZiBub3Qgc3BlY2lmaWVkLCB0aGUgZmlsdGVyIHBhcmFtZXRlciBvZiB0aGUgYG9wdGlvbnNgIG9iamVjdCBpcyB1c2VkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgYWRkVXNlcnM6IGZ1bmN0aW9uICh1c2Vycywgd29ybGRJZCwgb3B0aW9ucykge1xuXG4gICAgICAgICAgICBpZiAoIXVzZXJzKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhIGxpc3Qgb2YgdXNlcnMgdG8gYWRkIHRvIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBub3JtYWxpemUgdGhlIGxpc3Qgb2YgdXNlcnMgdG8gYW4gYXJyYXkgb2YgdXNlciBvYmplY3RzXG4gICAgICAgICAgICB1c2VycyA9ICQubWFwKFtdLmNvbmNhdCh1c2VycyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KHUpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1ICE9PSAnc3RyaW5nJyAmJiAhaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTb21lIG9mIHRoZSB1c2VycyBpbiB0aGUgbGlzdCBhcmUgbm90IGluIHRoZSB2YWxpZCBmb3JtYXQ6ICcgKyB1KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gaXNPYmplY3QgPyB1IDogeyB1c2VySWQ6IHUgfTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBjaGVjayBpZiBvcHRpb25zIHdlcmUgcGFzc2VkIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHdvcmxkSWQpICYmICFvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHdvcmxkSWQ7XG4gICAgICAgICAgICAgICAgd29ybGRJZCA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICAvLyB3ZSBtdXN0IGhhdmUgb3B0aW9ucyBieSBub3dcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygd29ybGRJZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvdXNlcnMnIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QodXNlcnMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIHJvbGUgb2YgYW4gZW5kIHVzZXIgaW4gYSBnaXZlbiB3b3JsZC4gKFlvdSBjYW4gb25seSB1cGRhdGUgb25lIGVuZCB1c2VyIGF0IGEgdGltZS4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuY3JlYXRlKCkudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgIHdhLnVwZGF0ZVVzZXIoeyB1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCByb2xlOiAnbGVhZGVyJyB9KTtcbiAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHVzZXJgIFVzZXIgb2JqZWN0IHdpdGggYHVzZXJJZGAgYW5kIHRoZSBuZXcgYHJvbGVgLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICghdXNlciB8fCAhdXNlci51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHBhc3MgYSB1c2VySWQgdG8gdXBkYXRlIGZyb20gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcGF0Y2hPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goX3BpY2sodXNlciwgJ3JvbGUnKSwgcGF0Y2hPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZW1vdmVzIGFuIGVuZCB1c2VyIGZyb20gYSBnaXZlbiB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5yZW1vdmVVc2VyKCdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoeyB1c2VySWQ6ICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdHxzdHJpbmd9IGB1c2VyYCBUaGUgYHVzZXJJZGAgb2YgdGhlIHVzZXIgdG8gcmVtb3ZlIGZyb20gdGhlIHdvcmxkLCBvciBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgYHVzZXJJZGAgZmllbGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdXNlciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICB1c2VyID0geyB1c2VySWQ6IHVzZXIgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHJ1biBpZCBvZiBjdXJyZW50IHJ1biBmb3IgdGhlIGdpdmVuIHdvcmxkLiBJZiB0aGUgd29ybGQgZG9lcyBub3QgaGF2ZSBhIHJ1biwgY3JlYXRlcyBhIG5ldyBvbmUgYW5kIHJldHVybnMgdGhlIHJ1biBpZC5cbiAgICAgICAgKlxuICAgICAgICAqIFJlbWVtYmVyIHRoYXQgYSBbcnVuXSguLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwuIEluIHRoZSBjYXNlIG9mIG11bHRpcGxheWVyIHByb2plY3RzLCB0aGUgcnVuIGlzIHNoYXJlZCBieSBhbGwgZW5kIHVzZXJzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRDdXJyZW50UnVuSWQoeyBtb2RlbDogJ21vZGVsLnB5JyB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRSdW5JZDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3J1bicgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoX3BpY2soZ2V0T3B0aW9ucywgJ21vZGVsJyksIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBmb3IgdGhlIGdpdmVuIGVuZCB1c2VyIGluIHRoZSBnaXZlbiBncm91cC4gQnJpbmdzIHRoaXMgbW9zdCByZWNlbnQgd29ybGQgaW50byBtZW1vcnkgaWYgbmVlZGVkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIHVzZSBkYXRhIGZyb20gd29ybGRcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSBjdXJyZW50IChtb3N0IHJlY2VudCkgd29ybGQgaXMgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cC4gSWYgbm90IHByb3ZpZGVkLCBkZWZhdWx0cyB0byB0aGUgZ3JvdXAgdXNlZCB0byBjcmVhdGUgdGhlIHNlcnZpY2UuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRXb3JsZEZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkc0ZvclVzZXIodXNlcklkLCB7IGdyb3VwOiBncm91cE5hbWUgfSlcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGFzc3VtZSB0aGUgbW9zdCByZWNlbnQgd29ybGQgYXMgdGhlICdhY3RpdmUnIHdvcmxkXG4gICAgICAgICAgICAgICAgICAgIHdvcmxkcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7IHJldHVybiBuZXcgRGF0ZShiLmxhc3RNb2RpZmllZCkgLSBuZXcgRGF0ZShhLmxhc3RNb2RpZmllZCk7IH0pO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VycmVudFdvcmxkID0gd29ybGRzWzBdO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50V29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9ICBjdXJyZW50V29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShjdXJyZW50V29ybGQsIG1lKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIHRoZSBjdXJyZW50IHJ1biBmcm9tIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIChOb3RlIHRoYXQgdGhlIHdvcmxkIGlkIHJlbWFpbnMgcGFydCBvZiB0aGUgcnVuIHJlY29yZCwgaW5kaWNhdGluZyB0aGF0IHRoZSBydW4gd2FzIGZvcm1lcmx5IGFuIGFjdGl2ZSBydW4gZm9yIHRoZSB3b3JsZC4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmRlbGV0ZVJ1bignc2FtcGxlLXdvcmxkLWlkJyk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSBgd29ybGRJZGAgb2YgdGhlIHdvcmxkIGZyb20gd2hpY2ggdGhlIGN1cnJlbnQgcnVuIGlzIGJlaW5nIGRlbGV0ZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGVSdW46IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBydW4gZm9yIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgd2EubmV3UnVuRm9yV29ybGQod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgd29ybGRJZCBpbiB3aGljaCB3ZSBjcmVhdGUgdGhlIG5ldyBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIG5ld1J1bkZvcldvcmxkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGN1cnJlbnRSdW5PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IGZpbHRlcjogd29ybGRJZCB8fCBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IoY3VycmVudFJ1bk9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kZWxldGVSdW4od29ybGRJZCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5nZXRDdXJyZW50UnVuSWQoY3VycmVudFJ1bk9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEFzc2lnbnMgZW5kIHVzZXJzIHRvIHdvcmxkcywgY3JlYXRpbmcgbmV3IHdvcmxkcyBhcyBhcHByb3ByaWF0ZSwgYXV0b21hdGljYWxseS4gQXNzaWducyBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cCwgYW5kIGNyZWF0ZXMgbmV3IHdvcmxkcyBhcyBuZWVkZWQgYmFzZWQgb24gdGhlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbiAocm9sZXMsIG9wdGlvbmFsIHJvbGVzLCBhbmQgbWluaW11bSBlbmQgdXNlcnMgcGVyIHdvcmxkKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5hdXRvQXNzaWduKCk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBhdXRvQXNzaWduOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhc3NpZ25tZW50RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBwYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3B0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgcHJvamVjdDogb3B0LnByb2plY3QsXG4gICAgICAgICAgICAgICAgZ3JvdXA6IG9wdC5ncm91cFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKG9wdC5tYXhVc2Vycykge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5tYXhVc2VycyA9IG9wdC5tYXhVc2VycztcbiAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgb3B0KTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBwcm9qZWN0J3Mgd29ybGQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgZXZlcnkgaW50ZXJhY3Rpb24gd2l0aCB5b3VyIHByb2plY3QgdXNlcyB0aGUgc2FtZSBjb25maWd1cmF0aW9uIG9mIGVhY2ggd29ybGQuIEZvciBleGFtcGxlLCBlYWNoIHdvcmxkIGluIHlvdXIgcHJvamVjdCBwcm9iYWJseSBoYXMgdGhlIHNhbWUgcm9sZXMgZm9yIGVuZCB1c2Vycy4gQW5kIHlvdXIgcHJvamVjdCBpcyBwcm9iYWJseSBlaXRoZXIgY29uZmlndXJlZCBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgc2hhcmUgdGhlIHNhbWUgd29ybGQgKGFuZCBydW4pLCBvciBzbWFsbGVyIHNldHMgb2YgZW5kIHVzZXJzIHNoYXJlIHdvcmxkcyDigJQgYnV0IG5vdCBib3RoLlxuICAgICAgICAqXG4gICAgICAgICogKFRoZSBbTXVsdGlwbGF5ZXIgUHJvamVjdCBSRVNUIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL211bHRpcGxheWVyX3Byb2plY3QvKSBhbGxvd3MgeW91IHRvIHNldCB0aGVzZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb25zLiBUaGUgV29ybGQgQWRhcHRlciBzaW1wbHkgcmV0cmlldmVzIHRoZW0sIGZvciBleGFtcGxlIHNvIHRoZXkgY2FuIGJlIHVzZWQgaW4gYXV0by1hc3NpZ25tZW50IG9mIGVuZCB1c2VycyB0byB3b3JsZHMuKVxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmdldFByb2plY3RTZXR0aW5ncygpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHNldHRpbmdzKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5yb2xlcyk7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5vcHRpb25hbFJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0UHJvamVjdFNldHRpbmdzOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChwcm9qZWN0RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIG9wdC51cmwgKz0gW29wdC5hY2NvdW50LCBvcHQucHJvamVjdF0uam9pbignLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQobnVsbCwgb3B0KTtcbiAgICAgICAgfVxuXG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29va2llIFN0b3JhZ2UgU2VydmljZVxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgIHZhciBwZW9wbGUgPSByZXF1aXJlKCdjb29raWUtc3RvcmUnKSh7IHJvb3Q6ICdwZW9wbGUnIH0pO1xuICAgICAgICBwZW9wbGVcbiAgICAgICAgICAgIC5zYXZlKHtsYXN0TmFtZTogJ3NtaXRoJyB9KVxuXG4gKi9cblxuXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5hbWUgb2YgY29sbGVjdGlvblxuICAgICAgICAgKiBAdHlwZSB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHJvb3Q6ICcvJyxcblxuICAgICAgICBkb21haW46ICcuZm9yaW8uY29tJ1xuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLy8gKiBUQkRcbiAgICAgICAgLy8gICogUXVlcnkgY29sbGVjdGlvbjsgdXNlcyBNb25nb0RCIHN5bnRheFxuICAgICAgICAvLyAgKiBAc2VlICA8VEJEOiBEYXRhIEFQSSBVUkw+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gcXMgUXVlcnkgRmlsdGVyXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gbGltaXRlcnMgQHNlZSA8VEJEOiB1cmwgZm9yIGxpbWl0cywgcGFnaW5nIGV0Yz5cbiAgICAgICAgLy8gICpcbiAgICAgICAgLy8gICogQGV4YW1wbGVcbiAgICAgICAgLy8gICogICAgIGNzLnF1ZXJ5KFxuICAgICAgICAvLyAgKiAgICAgIHsgbmFtZTogJ0pvaG4nLCBjbGFzc05hbWU6ICdDU0MxMDEnIH0sXG4gICAgICAgIC8vICAqICAgICAge2xpbWl0OiAxMH1cbiAgICAgICAgLy8gICogICAgIClcblxuICAgICAgICAvLyBxdWVyeTogZnVuY3Rpb24gKHFzLCBsaW1pdGVycykge1xuXG4gICAgICAgIC8vIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgY29va2llIHZhbHVlXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8T2JqZWN0fSBrZXkgICBJZiBnaXZlbiBhIGtleSBzYXZlIHZhbHVlcyB1bmRlciBpdCwgaWYgZ2l2ZW4gYW4gb2JqZWN0IGRpcmVjdGx5LCBzYXZlIHRvIHRvcC1sZXZlbCBhcGlcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSB2YWx1ZSAoT3B0aW9uYWwpXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIE92ZXJyaWRlcyBmb3Igc2VydmljZSBvcHRpb25zXG4gICAgICAgICAqXG4gICAgICAgICAqIEByZXR1cm4geyp9IFRoZSBzYXZlZCB2YWx1ZVxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3Muc2V0KCdwZXJzb24nLCB7IGZpcnN0TmFtZTogJ2pvaG4nLCBsYXN0TmFtZTogJ3NtaXRoJyB9KTtcbiAgICAgICAgICogICAgIGNzLnNldCh7IG5hbWU6J3NtaXRoJywgYWdlOiczMicgfSk7XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgc2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSBzZXRPcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2V0T3B0aW9ucy5yb290O1xuXG4gICAgICAgICAgICBkb2N1bWVudC5jb29raWUgPSBlbmNvZGVVUklDb21wb25lbnQoa2V5KSArICc9JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuY29kZVVSSUNvbXBvbmVudCh2YWx1ZSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG5cbiAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9hZCBjb29raWUgdmFsdWVcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSAgIElmIGdpdmVuIGEga2V5IHNhdmUgdmFsdWVzIHVuZGVyIGl0LCBpZiBnaXZlbiBhbiBvYmplY3QgZGlyZWN0bHksIHNhdmUgdG8gdG9wLWxldmVsIGFwaVxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgdmFsdWUgc3RvcmVkXG4gICAgICAgICAqXG4gICAgICAgICAqIEBleGFtcGxlXG4gICAgICAgICAqICAgICBjcy5nZXQoJ3BlcnNvbicpO1xuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgY29va2llUmVnID0gbmV3IFJlZ0V4cCgnKD86KD86XnwuKjspXFxcXHMqJyArIGVuY29kZVVSSUNvbXBvbmVudChrZXkpLnJlcGxhY2UoL1tcXC1cXC5cXCtcXCpdL2csICdcXFxcJCYnKSArICdcXFxccypcXFxcPVxcXFxzKihbXjtdKikuKiQpfF4uKiQnKTtcbiAgICAgICAgICAgIHZhciB2YWwgPSBkb2N1bWVudC5jb29raWUucmVwbGFjZShjb29raWVSZWcsICckMScpO1xuICAgICAgICAgICAgdmFsID0gZGVjb2RlVVJJQ29tcG9uZW50KHZhbCkgfHwgbnVsbDtcbiAgICAgICAgICAgIHJldHVybiB2YWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMga2V5IGZyb20gY29sbGVjdGlvblxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGtleSBrZXkgdG8gcmVtb3ZlXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9IGtleSBUaGUga2V5IHJlbW92ZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnJlbW92ZSgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciByZW1PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRvbWFpbiA9IHJlbU9wdGlvbnMuZG9tYWluO1xuICAgICAgICAgICAgdmFyIHBhdGggPSByZW1PcHRpb25zLnJvb3Q7XG5cbiAgICAgICAgICAgIGRvY3VtZW50LmNvb2tpZSA9IGVuY29kZVVSSUNvbXBvbmVudChrZXkpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPTsgZXhwaXJlcz1UaHUsIDAxIEphbiAxOTcwIDAwOjAwOjAwIEdNVCcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChkb21haW4gPyAnOyBkb21haW49JyArIGRvbWFpbiA6ICcnKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhdGggPyAnOyBwYXRoPScgKyBwYXRoIDogJycpO1xuICAgICAgICAgICAgcmV0dXJuIGtleTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgICogQHJldHVybiB7IGFycmF5fSBrZXlzIEFsbCB0aGUga2V5cyByZW1vdmVkXG4gICAgICAgICAqL1xuICAgICAgICBkZXN0cm95OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYUtleXMgPSBkb2N1bWVudC5jb29raWUucmVwbGFjZSgvKCg/Ol58XFxzKjspW15cXD1dKykoPz07fCQpfF5cXHMqfFxccyooPzpcXD1bXjtdKik/KD86XFwxfCQpL2csICcnKS5zcGxpdCgvXFxzKig/OlxcPVteO10qKT87XFxzKi8pO1xuICAgICAgICAgICAgZm9yICh2YXIgbklkeCA9IDA7IG5JZHggPCBhS2V5cy5sZW5ndGg7IG5JZHgrKykge1xuICAgICAgICAgICAgICAgIHZhciBjb29raWVLZXkgPSBkZWNvZGVVUklDb21wb25lbnQoYUtleXNbbklkeF0pO1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKGNvb2tpZUtleSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYUtleXM7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAgICBEZWNpZGVzIHR5cGUgb2Ygc3RvcmUgdG8gcHJvdmlkZVxuKi9cblxuJ3VzZSBzdHJpY3QnO1xuLy8gdmFyIGlzTm9kZSA9IGZhbHNlOyBGSVhNRTogQnJvd3NlcmlmeS9taW5pZnlpZnkgaGFzIGlzc3VlcyB3aXRoIHRoZSBuZXh0IGxpbmtcbi8vIHZhciBzdG9yZSA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9zZXNzaW9uLXN0b3JlJykgOiByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xudmFyIHN0b3JlID0gcmVxdWlyZSgnLi9jb29raWUtc3RvcmUnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBzdG9yZTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHF1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgdXJsOiAnJyxcblxuICAgICAgICBjb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICBoZWFkZXJzOiB7fSxcbiAgICAgICAgc3RhdHVzQ29kZToge1xuICAgICAgICAgICAgNDA0OiAkLm5vb3BcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT05MWSBmb3Igc3RyaW5ncyBpbiB0aGUgdXJsLiBBbGwgR0VUICYgREVMRVRFIHBhcmFtcyBhcmUgcnVuIHRocm91Z2ggdGhpc1xuICAgICAgICAgKiBAdHlwZSB7W3R5cGVdIH1cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFtZXRlclBhcnNlcjogcXV0aWxzLnRvUXVlcnlGb3JtYXQsXG5cbiAgICAgICAgLy8gVG8gYWxsb3cgZXBpY2VudGVyLnRva2VuIGFuZCBvdGhlciBzZXNzaW9uIGNvb2tpZXMgdG8gYmUgcGFzc2VkXG4gICAgICAgIC8vIHdpdGggdGhlIHJlcXVlc3RzXG4gICAgICAgIHhockZpZWxkczoge1xuICAgICAgICAgICAgd2l0aENyZWRlbnRpYWxzOiB0cnVlXG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG5cbiAgICB2YXIgcmVzdWx0ID0gZnVuY3Rpb24gKGQpIHtcbiAgICAgICAgcmV0dXJuICgkLmlzRnVuY3Rpb24oZCkpID8gZCgpIDogZDtcbiAgICB9O1xuXG4gICAgdmFyIGNvbm5lY3QgPSBmdW5jdGlvbiAobWV0aG9kLCBwYXJhbXMsIGNvbm5lY3RPcHRpb25zKSB7XG4gICAgICAgIHBhcmFtcyA9IHJlc3VsdChwYXJhbXMpO1xuICAgICAgICBwYXJhbXMgPSAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykgfHwgJC5pc0FycmF5KHBhcmFtcykpID8gSlNPTi5zdHJpbmdpZnkocGFyYW1zKSA6IHBhcmFtcztcblxuICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB0cmFuc3BvcnRPcHRpb25zLCBjb25uZWN0T3B0aW9ucywge1xuICAgICAgICAgICAgdHlwZTogbWV0aG9kLFxuICAgICAgICAgICAgZGF0YTogcGFyYW1zXG4gICAgICAgIH0pO1xuICAgICAgICB2YXIgQUxMT1dFRF9UT19CRV9GVU5DVElPTlMgPSBbJ2RhdGEnLCAndXJsJ107XG4gICAgICAgICQuZWFjaChvcHRpb25zLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgaWYgKCQuaXNGdW5jdGlvbih2YWx1ZSkgJiYgJC5pbkFycmF5KGtleSwgQUxMT1dFRF9UT19CRV9GVU5DVElPTlMpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnNba2V5XSA9IHZhbHVlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChvcHRpb25zLmxvZ0xldmVsICYmIG9wdGlvbnMubG9nTGV2ZWwgPT09ICdERUJVRycpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKG9wdGlvbnMudXJsKTtcbiAgICAgICAgICAgIHZhciBvbGRTdWNjZXNzRm4gPSBvcHRpb25zLnN1Y2Nlc3MgfHwgJC5ub29wO1xuICAgICAgICAgICAgb3B0aW9ucy5zdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlLCBhamF4U3RhdHVzLCBhamF4UmVxKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2cocmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3NGbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBiZWZvcmVTZW5kID0gb3B0aW9ucy5iZWZvcmVTZW5kO1xuICAgICAgICBvcHRpb25zLmJlZm9yZVNlbmQgPSBmdW5jdGlvbiAoeGhyLCBzZXR0aW5ncykge1xuICAgICAgICAgICAgeGhyLnJlcXVlc3RVcmwgPSAoY29ubmVjdE9wdGlvbnMgfHwge30pLnVybDtcbiAgICAgICAgICAgIGlmIChiZWZvcmVTZW5kKSB7XG4gICAgICAgICAgICAgICAgYmVmb3JlU2VuZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiAkLmFqYXgob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIGdldDpmdW5jdGlvbiAocGFyYW1zLCBhamF4T3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgdHJhbnNwb3J0T3B0aW9ucywgYWpheE9wdGlvbnMpO1xuICAgICAgICAgICAgcGFyYW1zID0gb3B0aW9ucy5wYXJhbWV0ZXJQYXJzZXIocmVzdWx0KHBhcmFtcykpO1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuY2FsbCh0aGlzLCAnR0VUJywgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgc3BsaXRHZXQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB9LFxuICAgICAgICBwb3N0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ3Bvc3QnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHBhdGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ3BhdGNoJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBwdXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncHV0J10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBkZWxldGU6IGZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICAvL0RFTEVURSBkb2Vzbid0IHN1cHBvcnQgYm9keSBwYXJhbXMsIGJ1dCBqUXVlcnkgdGhpbmtzIGl0IGRvZXMuXG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICBpZiAoJC50cmltKHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICB2YXIgZGVsaW1pdGVyID0gKHJlc3VsdChvcHRpb25zLnVybCkuaW5kZXhPZignPycpID09PSAtMSkgPyAnPycgOiAnJic7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy51cmwgPSByZXN1bHQob3B0aW9ucy51cmwpICsgZGVsaW1pdGVyICsgcGFyYW1zO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuY2FsbCh0aGlzLCAnREVMRVRFJywgbnVsbCwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG4gICAgICAgIGhlYWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsnaGVhZCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgb3B0aW9uczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydvcHRpb25zJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHJldHVybiAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gdmFyIGlzTm9kZSA9IGZhbHNlOyBGSVhNRTogQnJvd3NlcmlmeS9taW5pZnlpZnkgaGFzIGlzc3VlcyB3aXRoIHRoZSBuZXh0IGxpbmtcbi8vIHZhciB0cmFuc3BvcnQgPSAoaXNOb2RlKSA/IHJlcXVpcmUoJy4vbm9kZS1odHRwLXRyYW5zcG9ydCcpIDogcmVxdWlyZSgnLi9hamF4LWh0dHAtdHJhbnNwb3J0Jyk7XG52YXIgdHJhbnNwb3J0ID0gcmVxdWlyZSgnLi9hamF4LWh0dHAtdHJhbnNwb3J0Jyk7XG5tb2R1bGUuZXhwb3J0cyA9IHRyYW5zcG9ydDtcbiIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiIsIid1c2Ugc3RyaWN0Jztcbi8qanNoaW50IGxvb3BmdW5jOmZhbHNlICovXG5cbmZ1bmN0aW9uIF93KHZhbCkge1xuICAgIGlmICh2YWwgJiYgdmFsLnRoZW4pIHtcbiAgICAgICAgcmV0dXJuIHZhbDtcbiAgICB9XG4gICAgdmFyIHAgPSAkLkRlZmVycmVkKCk7XG4gICAgcC5yZXNvbHZlKHZhbCk7XG5cbiAgICByZXR1cm4gcC5wcm9taXNlKCk7XG59XG5cbmZ1bmN0aW9uIHNlcSgpIHtcbiAgICB2YXIgbGlzdCA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMpO1xuXG4gICAgZnVuY3Rpb24gbmV4dChwKSB7XG4gICAgICAgIHZhciBjdXIgPSBsaXN0LnNwbGljZSgwLDEpWzBdO1xuXG4gICAgICAgIGlmICghY3VyKSB7XG4gICAgICAgICAgICByZXR1cm4gcDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBfdyhjdXIocCkpLnRoZW4obmV4dCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZ1bmN0aW9uIChzZWVkKSB7XG4gICAgICAgIHJldHVybiBuZXh0KHNlZWQpLmZhaWwoc2VxLmZhaWwpO1xuICAgIH07XG59XG5cbmZ1bmN0aW9uIE1ha2VTZXEob2JqKSB7XG4gICAgdmFyIHJlcyA9IHtcbiAgICAgICAgX19jYWxsczogW10sXG5cbiAgICAgICAgb3JpZ2luYWw6IG9iaixcblxuICAgICAgICB0aGVuOiBmdW5jdGlvbiAoZm4pIHtcbiAgICAgICAgICAgIHRoaXMuX19jYWxscy5wdXNoKGZuKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIHN0YXJ0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgICAgICAvLyBjbGVhbiB1cFxuICAgICAgICAgICAgdGhpcy50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICBfdGhpcy5fX2NhbGxzLmxlbmd0aCA9IDA7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gc2VxLmFwcGx5KG51bGwsIHRoaXMuX19jYWxscykoKTtcbiAgICAgICAgfSxcblxuICAgICAgICBmYWlsOiBmdW5jdGlvbiAoZm4pIHtcbiAgICAgICAgICAgIHNlcS5mYWlsID0gZm47XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgZnVuY01ha2VyID0gZnVuY3Rpb24gKHAsIG9iaikge1xuICAgICAgICB2YXIgZm4gPSBvYmpbcF0uYmluZChvYmopO1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuYXBwbHkoYXJndW1lbnRzKTtcbiAgICAgICAgICAgIHRoaXMuX19jYWxscy5wdXNoKEZ1bmN0aW9uLmJpbmQuYXBwbHkoZm4sIFtudWxsXS5jb25jYXQoYXJncykpKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9O1xuICAgIH07XG5cbiAgICBmb3IgKHZhciBwcm9wIGluIG9iaikge1xuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgcmVzW3Byb3BdID0gZnVuY01ha2VyKHByb3AsIG9iaik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXNbcHJvcF0gPSBvYmpbcHJvcF07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcmVzO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IE1ha2VTZXE7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIF9waWNrOiBmdW5jdGlvbiAob2JqLCBwcm9wcykge1xuICAgICAgICB2YXIgcmVzID0ge307XG4gICAgICAgIGZvciAodmFyIHAgaW4gb2JqKSB7XG4gICAgICAgICAgICBpZiAocHJvcHMuaW5kZXhPZihwKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICByZXNbcF0gPSBvYmpbcF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cbn07XG4iLCIvKipcbiAqIFV0aWxpdGllcyBmb3Igd29ya2luZyB3aXRoIHF1ZXJ5IHN0cmluZ3NcbiovXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gKGZ1bmN0aW9uICgpIHtcblxuICAgIHJldHVybiB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyB0byBtYXRyaXggZm9ybWF0XG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gcXMgT2JqZWN0IHRvIGNvbnZlcnQgdG8gcXVlcnkgc3RyaW5nXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9ICAgIE1hdHJpeC1mb3JtYXQgcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAgKi9cbiAgICAgICAgdG9NYXRyaXhGb3JtYXQ6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQgfHwgcXMgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICc7JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcXMgPT09ICdzdHJpbmcnIHx8IHFzIGluc3RhbmNlb2YgU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHFzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcmV0dXJuQXJyYXkgPSBbXTtcbiAgICAgICAgICAgIHZhciBPUEVSQVRPUlMgPSBbJzwnLCAnPicsICchJ107XG4gICAgICAgICAgICAkLmVhY2gocXMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3N0cmluZycgfHwgJC5pbkFycmF5KCQudHJpbSh2YWx1ZSkuY2hhckF0KDApLCBPUEVSQVRPUlMpID09PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9ICc9JyArIHZhbHVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5BcnJheS5wdXNoKGtleSArIHZhbHVlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB2YXIgbXRyeCA9ICc7JyArIHJldHVybkFycmF5LmpvaW4oJzsnKTtcbiAgICAgICAgICAgIHJldHVybiBtdHJ4O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyBzdHJpbmdzL2FycmF5cy9vYmplY3RzIHRvIHR5cGUgJ2E9YiZiPWMnXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxc1xuICAgICAgICAgKiBAcmV0dXJuIHsgc3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9RdWVyeUZvcm1hdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcXMgPT09ICdzdHJpbmcnIHx8IHFzIGluc3RhbmNlb2YgU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHFzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcmV0dXJuQXJyYXkgPSBbXTtcbiAgICAgICAgICAgICQuZWFjaChxcywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlLmpvaW4oJywnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdCh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy9Nb3N0bHkgZm9yIGRhdGEgYXBpXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5BcnJheS5wdXNoKGtleSArICc9JyArIHZhbHVlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gcmV0dXJuQXJyYXkuam9pbignJicpO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgc3RyaW5ncyBvZiB0eXBlICdhPWImYj1jJyB0byB7IGE6YiwgYjpjfVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfSBxc1xuICAgICAgICAgKiBAcmV0dXJuIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBxc1RvT2JqZWN0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkIHx8IHFzID09PSAnJykge1xuICAgICAgICAgICAgICAgIHJldHVybiB7fTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHFzQXJyYXkgPSBxcy5zcGxpdCgnJicpO1xuICAgICAgICAgICAgdmFyIHJldHVybk9iaiA9IHt9O1xuICAgICAgICAgICAgJC5lYWNoKHFzQXJyYXksIGZ1bmN0aW9uIChpbmRleCwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICB2YXIgcUtleSA9IHZhbHVlLnNwbGl0KCc9JylbMF07XG4gICAgICAgICAgICAgICAgdmFyIHFWYWwgPSB2YWx1ZS5zcGxpdCgnPScpWzFdO1xuXG4gICAgICAgICAgICAgICAgaWYgKHFWYWwuaW5kZXhPZignLCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICBxVmFsID0gcVZhbC5zcGxpdCgnLCcpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybk9ialtxS2V5XSA9IHFWYWw7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIHJldHVybk9iajtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTm9ybWFsaXplcyBhbmQgbWVyZ2VzIHN0cmluZ3Mgb2YgdHlwZSAnYT1iJywgeyBiOmN9IHRvIHsgYTpiLCBiOmN9XG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxczFcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzMlxuICAgICAgICAgKiBAcmV0dXJuIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBtZXJnZVFTOiBmdW5jdGlvbiAocXMxLCBxczIpIHtcbiAgICAgICAgICAgIHZhciBvYmoxID0gdGhpcy5xc1RvT2JqZWN0KHRoaXMudG9RdWVyeUZvcm1hdChxczEpKTtcbiAgICAgICAgICAgIHZhciBvYmoyID0gdGhpcy5xc1RvT2JqZWN0KHRoaXMudG9RdWVyeUZvcm1hdChxczIpKTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCB7fSwgb2JqMSwgb2JqMik7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYWRkVHJhaWxpbmdTbGFzaDogZnVuY3Rpb24gKHVybCkge1xuICAgICAgICAgICAgaWYgKCF1cmwpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gKHVybC5jaGFyQXQodXJsLmxlbmd0aCAtIDEpID09PSAnLycpID8gdXJsIDogKHVybCArICcvJyk7XG4gICAgICAgIH1cbiAgICB9O1xufSgpKTtcblxuXG5cbiIsIi8qKlxuICogVXRpbGl0aWVzIGZvciB3b3JraW5nIHdpdGggdGhlIHJ1biBzZXJ2aWNlXG4qL1xuJ3VzZSBzdHJpY3QnO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi9xdWVyeS11dGlsJyk7XG52YXIgTUFYX1VSTF9MRU5HVEggPSAyMDQ4O1xuXG5tb2R1bGUuZXhwb3J0cyA9IChmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIHJldHVybnMgb3BlcmF0aW9ucyBvZiB0aGUgZm9ybSBgW1tvcDEsb3AyXSwgW2FyZzEsIGFyZzJdXWBcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fEFycmF5fFN0cmluZ30gYG9wZXJhdGlvbnNgIG9wZXJhdGlvbnMgdG8gcGVyZm9ybVxuICAgICAgICAgKiBAcGFyYW0gIHtBcnJheX0gYGFyZ3NgIGFyZ3VtZW50cyBmb3Igb3BlcmF0aW9uXG4gICAgICAgICAqIEByZXR1cm4ge1N0cmluZ30gICAgTWF0cml4LWZvcm1hdCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuICAgICAgICBub3JtYWxpemVPcGVyYXRpb25zOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgYXJncykge1xuICAgICAgICAgICAgaWYgKCFhcmdzKSB7XG4gICAgICAgICAgICAgICAgYXJncyA9IFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJldHVybkxpc3QgPSB7XG4gICAgICAgICAgICAgICAgb3BzOiBbXSxcbiAgICAgICAgICAgICAgICBhcmdzOiBbXVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9jb25jYXQgPSBmdW5jdGlvbiAoYXJyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIChhcnIgIT09IG51bGwgJiYgYXJyICE9PSB1bmRlZmluZWQpID8gW10uY29uY2F0KGFycikgOiBbXTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIC8veyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfVxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVQbGFpbk9iamVjdHMgPSBmdW5jdGlvbiAob3BlcmF0aW9ucywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAkLmVhY2gob3BlcmF0aW9ucywgZnVuY3Rpb24gKG9wbiwgYXJnKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BuKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChhcmcpKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAvL3sgbmFtZTogJ2FkZCcsIHBhcmFtczogWzFdIH1cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplU3RydWN0dXJlZE9iamVjdHMgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BlcmF0aW9uLm5hbWUpO1xuICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQob3BlcmF0aW9uLnBhcmFtcykpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVPYmplY3QgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICgob3BlcmF0aW9uLm5hbWUpID8gX25vcm1hbGl6ZVN0cnVjdHVyZWRPYmplY3RzIDogX25vcm1hbGl6ZVBsYWluT2JqZWN0cykob3BlcmF0aW9uLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplTGl0ZXJhbHMgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBhcmdzLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BlcmF0aW9uKTtcbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KGFyZ3MpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVBcnJheXMgPSBmdW5jdGlvbiAob3BlcmF0aW9ucywgYXJnLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICQuZWFjaChvcGVyYXRpb25zLCBmdW5jdGlvbiAoaW5kZXgsIG9wbikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KG9wbikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIF9ub3JtYWxpemVPYmplY3Qob3BuLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIF9ub3JtYWxpemVMaXRlcmFscyhvcG4sIGFyZ3NbaW5kZXhdLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChvcGVyYXRpb25zKSkge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVPYmplY3Qob3BlcmF0aW9ucywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCQuaXNBcnJheShvcGVyYXRpb25zKSkge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVBcnJheXMob3BlcmF0aW9ucywgYXJncywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVMaXRlcmFscyhvcGVyYXRpb25zLCBhcmdzLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3BsaXRHZXRGYWN0b3J5OiBmdW5jdGlvbiAoaHR0cE9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgdmFyIGh0dHAgPSB0aGlzO1xuICAgICAgICAgICAgICAgIHZhciBnZXRWYWx1ZSA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB2YWx1ZSA9IG9wdGlvbnNbbmFtZV0gfHwgaHR0cE9wdGlvbnNbbmFtZV07XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgZ2V0RmluYWxVcmwgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB1cmwgPSBnZXRWYWx1ZSgndXJsJywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkYXRhID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICAvLyBUaGVyZSBpcyBlYXN5IChvciBrbm93bikgd2F5IHRvIGdldCB0aGUgZmluYWwgVVJMIGpxdWVyeSBpcyBnb2luZyB0byBzZW5kIHNvXG4gICAgICAgICAgICAgICAgICAgIC8vIHdlJ3JlIHJlcGxpY2F0aW5nIGl0LiBUaGUgcHJvY2VzcyBtaWdodCBjaGFuZ2UgYXQgc29tZSBwb2ludCBidXQgaXQgcHJvYmFibHkgd2lsbCBub3QuXG4gICAgICAgICAgICAgICAgICAgIC8vIDEuIFJlbW92ZSBoYXNoXG4gICAgICAgICAgICAgICAgICAgIHVybCA9IHVybC5yZXBsYWNlKC8jLiokLywgJycpO1xuICAgICAgICAgICAgICAgICAgICAvLyAxLiBBcHBlbmQgcXVlcnkgc3RyaW5nXG4gICAgICAgICAgICAgICAgICAgIHZhciBxdWVyeVBhcmFtcyA9IHF1dGlsLnRvUXVlcnlGb3JtYXQoZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBxdWVzdGlvbklkeCA9IHVybC5pbmRleE9mKCc/Jyk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChxdWVyeVBhcmFtcyAmJiBxdWVzdGlvbklkeCA+IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsICsgJyYnICsgcXVlcnlQYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocXVlcnlQYXJhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmwgKyAnPycgKyBxdWVyeVBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIHVybCA9IGdldEZpbmFsVXJsKHBhcmFtcyk7XG4gICAgICAgICAgICAgICAgLy8gV2UgbXVzdCBzcGxpdCB0aGUgR0VUIGluIG11bHRpcGxlIHNob3J0IFVSTCdzXG4gICAgICAgICAgICAgICAgLy8gVGhlIG9ubHkgcHJvcGVydHkgYWxsb3dlZCB0byBiZSBzcGxpdCBpcyBcImluY2x1ZGVcIlxuICAgICAgICAgICAgICAgIGlmIChwYXJhbXMgJiYgcGFyYW1zLmluY2x1ZGUgJiYgdXJsLmxlbmd0aCA+IE1BWF9VUkxfTEVOR1RIKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBwYXJhbXNDb3B5ID0gJC5leHRlbmQodHJ1ZSwge30sIHBhcmFtcyk7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBwYXJhbXNDb3B5LmluY2x1ZGU7XG4gICAgICAgICAgICAgICAgICAgIHZhciB1cmxOb0luY2x1ZGVzID0gZ2V0RmluYWxVcmwocGFyYW1zQ29weSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkaWZmID0gTUFYX1VSTF9MRU5HVEggLSB1cmxOb0luY2x1ZGVzLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBvcHRpb25zLnN1Y2Nlc3MgfHwgaHR0cE9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIHZhciBvbGRFcnJvciA9IG9wdGlvbnMuZXJyb3IgfHwgaHR0cE9wdGlvbnMuZXJyb3IgfHwgJC5ub29wO1xuICAgICAgICAgICAgICAgICAgICAvLyByZW1vdmUgdGhlIG9yaWdpbmFsIHN1Y2Nlc3MgYW5kIGVycm9yIGNhbGxiYWNrc1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZXJyb3IgPSAkLm5vb3A7XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIGluY2x1ZGUgPSBwYXJhbXMuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1cnJJbmNsdWRlcyA9IFtdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZU9wdHMgPSBbY3VyckluY2x1ZGVzXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1cnJMZW5ndGggPSAnP2luY2x1ZGU9Jy5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIHZhciB2YXJpYWJsZSA9IGluY2x1ZGUucG9wKCk7XG4gICAgICAgICAgICAgICAgICAgIHdoaWxlICh2YXJpYWJsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVXNlIGEgZ3JlZWR5IGFwcHJvYWNoIGZvciBub3csIGNhbiBiZSBvcHRpbWl6ZWQgdG8gYmUgc29sdmVkIGluIGEgbW9yZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZWZmaWNpZW50IHdheVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gKyAxIGlzIHRoZSBjb21tYVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGN1cnJMZW5ndGggKyB2YXJpYWJsZS5sZW5ndGggKyAxIDwgZGlmZikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJJbmNsdWRlcy5wdXNoKHZhcmlhYmxlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyTGVuZ3RoICs9IHZhcmlhYmxlLmxlbmd0aCArIDE7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJJbmNsdWRlcyA9IFt2YXJpYWJsZV07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZU9wdHMucHVzaChjdXJySW5jbHVkZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJMZW5ndGggPSAnP2luY2x1ZGU9Jy5sZW5ndGggKyB2YXJpYWJsZS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZSA9IGluY2x1ZGUucG9wKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdmFyIHJlcXMgPSAkLm1hcChpbmNsdWRlT3B0cywgZnVuY3Rpb24gKGluY2x1ZGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZXFQYXJhbXMgPSAkLmV4dGVuZCh7fSwgcGFyYW1zLCB7IGluY2x1ZGU6IGluY2x1ZGUgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQocmVxUGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICQud2hlbi5hcHBseSgkLCByZXFzKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEVhY2ggYXJndW1lbnQgYXJlIGFycmF5cyBvZiB0aGUgYXJndW1lbnRzIG9mIGVhY2ggZG9uZSByZXF1ZXN0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBTbyB0aGUgZmlyc3QgYXJndW1lbnQgb2YgdGhlIGZpcnN0IGFycmF5IG9mIGFyZ3VtZW50cyBpcyB0aGUgZGF0YVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGlzVmFsaWQgPSBhcmd1bWVudHNbMF0gJiYgYXJndW1lbnRzWzBdWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFpc1ZhbGlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2hvdWxkIG5ldmVyIGhhcHBlbi4uLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZEVycm9yKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBmaXJzdFJlc3BvbnNlID0gYXJndW1lbnRzWzBdWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KGZpcnN0UmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGlzUnVuQVBJID0gKGlzT2JqZWN0ICYmICQuaXNQbGFpbk9iamVjdChmaXJzdFJlc3BvbnNlLnZhcmlhYmxlcykpIHx8ICFpc09iamVjdDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc1J1bkFQSSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc09iamVjdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhZ2dyZWdhdGUgdGhlIHZhcmlhYmxlcyBwcm9wZXJ0eSBvbmx5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVSdW4gPSBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChhcmd1bWVudHMsIGZ1bmN0aW9uIChpZHgsIGFyZ3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBydW4gPSBhcmdzWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5leHRlbmQodHJ1ZSwgYWdncmVnYXRlUnVuLnZhcmlhYmxlcywgcnVuLnZhcmlhYmxlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZVJ1biwgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShhZ2dyZWdhdGVSdW4sIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhcnJheSBvZiBydW5zXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFncmVnYXRlIHZhcmlhYmxlcyBpbiBlYWNoIHJ1blxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgYWdncmVnYXRlZFJ1bnMgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJ1bnMgPSBhcmdzWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEkLmlzQXJyYXkocnVucykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2gocnVucywgZnVuY3Rpb24gKGlkeFJ1biwgcnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJ1bi5pZCAmJiAhYWdncmVnYXRlZFJ1bnNbcnVuLmlkXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBydW4udmFyaWFibGVzID0gcnVuLnZhcmlhYmxlcyB8fCB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdncmVnYXRlZFJ1bnNbcnVuLmlkXSA9IHJ1bjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHJ1bi5pZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVkUnVuc1tydW4uaWRdLnZhcmlhYmxlcywgcnVuLnZhcmlhYmxlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0dXJuIGl0IGludG8gYW4gYXJyYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdncmVnYXRlZFJ1bnMgPSAkLm1hcChhZ2dyZWdhdGVkUnVucywgZnVuY3Rpb24gKHJ1bikgeyByZXR1cm4gcnVuOyB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkU3VjY2VzcyhhZ2dyZWdhdGVkUnVucywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShhZ2dyZWdhdGVkUnVucywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXMgdmFyaWFibGVzIEFQSVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnZ3JlZ2F0ZSB0aGUgcmVzcG9uc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgYWdncmVnYXRlZFZhcmlhYmxlcyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChhcmd1bWVudHMsIGZ1bmN0aW9uIChpZHgsIGFyZ3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHZhcnMgPSBhcmdzWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVkVmFyaWFibGVzLCB2YXJzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShhZ2dyZWdhdGVkVmFyaWFibGVzLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0sIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9sZEVycm9yLmFwcGx5KGh0dHAsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVqZWN0LmFwcGx5KGR0ZCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9O1xufSgpKTtcbiJdfQ== +//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL25vZGVfbW9kdWxlcy9pZWVlNzU0L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvaXMtYXJyYXkvaW5kZXguanMiLCJzcmMvYXBpLXZlcnNpb24uanNvbiIsInNyYy9hcHAuanMiLCJzcmMvbWFuYWdlcnMvYXV0aC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2NoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2tleS1uYW1lcy5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9hbHdheXMtbmV3LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2lkZW50aXR5LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL211bHRpcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcC5qcyIsInNyYy9tYW5hZ2Vycy9zY2VuYXJpby1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3NwZWNpYWwtb3BlcmF0aW9ucy5qcyIsInNyYy9tYW5hZ2Vycy93b3JsZC1tYW5hZ2VyLmpzIiwic3JjL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyLmpzIiwic3JjL3N0b3JlL2Nvb2tpZS1zdG9yZS5qcyIsInNyYy9zdG9yZS9zdG9yZS1mYWN0b3J5LmpzIiwic3JjL3RyYW5zcG9ydC9hamF4LWh0dHAtdHJhbnNwb3J0LmpzIiwic3JjL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5LmpzIiwic3JjL3V0aWwvaW5oZXJpdC5qcyIsInNyYy91dGlsL21ha2Utc2VxdWVuY2UuanMiLCJzcmMvdXRpbC9vYmplY3QtdXRpbC5qcyIsInNyYy91dGlsL3F1ZXJ5LXV0aWwuanMiLCJzcmMvdXRpbC9ydW4tdXRpbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN4Z0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2V0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMVRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0UUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25LQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzdUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLyohXG4gKiBUaGUgYnVmZmVyIG1vZHVsZSBmcm9tIG5vZGUuanMsIGZvciB0aGUgYnJvd3Nlci5cbiAqXG4gKiBAYXV0aG9yICAgRmVyb3NzIEFib3VraGFkaWplaCA8ZmVyb3NzQGZlcm9zcy5vcmc+IDxodHRwOi8vZmVyb3NzLm9yZz5cbiAqIEBsaWNlbnNlICBNSVRcbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tcHJvdG8gKi9cblxudmFyIGJhc2U2NCA9IHJlcXVpcmUoJ2Jhc2U2NC1qcycpXG52YXIgaWVlZTc1NCA9IHJlcXVpcmUoJ2llZWU3NTQnKVxudmFyIGlzQXJyYXkgPSByZXF1aXJlKCdpcy1hcnJheScpXG5cbmV4cG9ydHMuQnVmZmVyID0gQnVmZmVyXG5leHBvcnRzLlNsb3dCdWZmZXIgPSBTbG93QnVmZmVyXG5leHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTID0gNTBcbkJ1ZmZlci5wb29sU2l6ZSA9IDgxOTIgLy8gbm90IHVzZWQgYnkgdGhpcyBpbXBsZW1lbnRhdGlvblxuXG52YXIgcm9vdFBhcmVudCA9IHt9XG5cbi8qKlxuICogSWYgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYDpcbiAqICAgPT09IHRydWUgICAgVXNlIFVpbnQ4QXJyYXkgaW1wbGVtZW50YXRpb24gKGZhc3Rlc3QpXG4gKiAgID09PSBmYWxzZSAgIFVzZSBPYmplY3QgaW1wbGVtZW50YXRpb24gKG1vc3QgY29tcGF0aWJsZSwgZXZlbiBJRTYpXG4gKlxuICogQnJvd3NlcnMgdGhhdCBzdXBwb3J0IHR5cGVkIGFycmF5cyBhcmUgSUUgMTArLCBGaXJlZm94IDQrLCBDaHJvbWUgNyssIFNhZmFyaSA1LjErLFxuICogT3BlcmEgMTEuNissIGlPUyA0LjIrLlxuICpcbiAqIER1ZSB0byB2YXJpb3VzIGJyb3dzZXIgYnVncywgc29tZXRpbWVzIHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24gd2lsbCBiZSB1c2VkIGV2ZW5cbiAqIHdoZW4gdGhlIGJyb3dzZXIgc3VwcG9ydHMgdHlwZWQgYXJyYXlzLlxuICpcbiAqIE5vdGU6XG4gKlxuICogICAtIEZpcmVmb3ggNC0yOSBsYWNrcyBzdXBwb3J0IGZvciBhZGRpbmcgbmV3IHByb3BlcnRpZXMgdG8gYFVpbnQ4QXJyYXlgIGluc3RhbmNlcyxcbiAqICAgICBTZWU6IGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTY5NTQzOC5cbiAqXG4gKiAgIC0gU2FmYXJpIDUtNyBsYWNrcyBzdXBwb3J0IGZvciBjaGFuZ2luZyB0aGUgYE9iamVjdC5wcm90b3R5cGUuY29uc3RydWN0b3JgIHByb3BlcnR5XG4gKiAgICAgb24gb2JqZWN0cy5cbiAqXG4gKiAgIC0gQ2hyb21lIDktMTAgaXMgbWlzc2luZyB0aGUgYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbi5cbiAqXG4gKiAgIC0gSUUxMCBoYXMgYSBicm9rZW4gYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGFycmF5cyBvZlxuICogICAgIGluY29ycmVjdCBsZW5ndGggaW4gc29tZSBzaXR1YXRpb25zLlxuXG4gKiBXZSBkZXRlY3QgdGhlc2UgYnVnZ3kgYnJvd3NlcnMgYW5kIHNldCBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgIHRvIGBmYWxzZWAgc28gdGhleVxuICogZ2V0IHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24sIHdoaWNoIGlzIHNsb3dlciBidXQgYmVoYXZlcyBjb3JyZWN0bHkuXG4gKi9cbkJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUID0gZ2xvYmFsLlRZUEVEX0FSUkFZX1NVUFBPUlQgIT09IHVuZGVmaW5lZFxuICA/IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gIDogdHlwZWRBcnJheVN1cHBvcnQoKVxuXG5mdW5jdGlvbiB0eXBlZEFycmF5U3VwcG9ydCAoKSB7XG4gIGZ1bmN0aW9uIEJhciAoKSB7fVxuICB0cnkge1xuICAgIHZhciBhcnIgPSBuZXcgVWludDhBcnJheSgxKVxuICAgIGFyci5mb28gPSBmdW5jdGlvbiAoKSB7IHJldHVybiA0MiB9XG4gICAgYXJyLmNvbnN0cnVjdG9yID0gQmFyXG4gICAgcmV0dXJuIGFyci5mb28oKSA9PT0gNDIgJiYgLy8gdHlwZWQgYXJyYXkgaW5zdGFuY2VzIGNhbiBiZSBhdWdtZW50ZWRcbiAgICAgICAgYXJyLmNvbnN0cnVjdG9yID09PSBCYXIgJiYgLy8gY29uc3RydWN0b3IgY2FuIGJlIHNldFxuICAgICAgICB0eXBlb2YgYXJyLnN1YmFycmF5ID09PSAnZnVuY3Rpb24nICYmIC8vIGNocm9tZSA5LTEwIGxhY2sgYHN1YmFycmF5YFxuICAgICAgICBhcnIuc3ViYXJyYXkoMSwgMSkuYnl0ZUxlbmd0aCA9PT0gMCAvLyBpZTEwIGhhcyBicm9rZW4gYHN1YmFycmF5YFxuICB9IGNhdGNoIChlKSB7XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuZnVuY3Rpb24ga01heExlbmd0aCAoKSB7XG4gIHJldHVybiBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVFxuICAgID8gMHg3ZmZmZmZmZlxuICAgIDogMHgzZmZmZmZmZlxufVxuXG4vKipcbiAqIENsYXNzOiBCdWZmZXJcbiAqID09PT09PT09PT09PT1cbiAqXG4gKiBUaGUgQnVmZmVyIGNvbnN0cnVjdG9yIHJldHVybnMgaW5zdGFuY2VzIG9mIGBVaW50OEFycmF5YCB0aGF0IGFyZSBhdWdtZW50ZWRcbiAqIHdpdGggZnVuY3Rpb24gcHJvcGVydGllcyBmb3IgYWxsIHRoZSBub2RlIGBCdWZmZXJgIEFQSSBmdW5jdGlvbnMuIFdlIHVzZVxuICogYFVpbnQ4QXJyYXlgIHNvIHRoYXQgc3F1YXJlIGJyYWNrZXQgbm90YXRpb24gd29ya3MgYXMgZXhwZWN0ZWQgLS0gaXQgcmV0dXJuc1xuICogYSBzaW5nbGUgb2N0ZXQuXG4gKlxuICogQnkgYXVnbWVudGluZyB0aGUgaW5zdGFuY2VzLCB3ZSBjYW4gYXZvaWQgbW9kaWZ5aW5nIHRoZSBgVWludDhBcnJheWBcbiAqIHByb3RvdHlwZS5cbiAqL1xuZnVuY3Rpb24gQnVmZmVyIChhcmcpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIEJ1ZmZlcikpIHtcbiAgICAvLyBBdm9pZCBnb2luZyB0aHJvdWdoIGFuIEFyZ3VtZW50c0FkYXB0b3JUcmFtcG9saW5lIGluIHRoZSBjb21tb24gY2FzZS5cbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIHJldHVybiBuZXcgQnVmZmVyKGFyZywgYXJndW1lbnRzWzFdKVxuICAgIHJldHVybiBuZXcgQnVmZmVyKGFyZylcbiAgfVxuXG4gIHRoaXMubGVuZ3RoID0gMFxuICB0aGlzLnBhcmVudCA9IHVuZGVmaW5lZFxuXG4gIC8vIENvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ251bWJlcicpIHtcbiAgICByZXR1cm4gZnJvbU51bWJlcih0aGlzLCBhcmcpXG4gIH1cblxuICAvLyBTbGlnaHRseSBsZXNzIGNvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gZnJvbVN0cmluZyh0aGlzLCBhcmcsIGFyZ3VtZW50cy5sZW5ndGggPiAxID8gYXJndW1lbnRzWzFdIDogJ3V0ZjgnKVxuICB9XG5cbiAgLy8gVW51c3VhbC5cbiAgcmV0dXJuIGZyb21PYmplY3QodGhpcywgYXJnKVxufVxuXG5mdW5jdGlvbiBmcm9tTnVtYmVyICh0aGF0LCBsZW5ndGgpIHtcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aCA8IDAgPyAwIDogY2hlY2tlZChsZW5ndGgpIHwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHRoYXRbaV0gPSAwXG4gICAgfVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21TdHJpbmcgKHRoYXQsIHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBlbmNvZGluZyAhPT0gJ3N0cmluZycgfHwgZW5jb2RpbmcgPT09ICcnKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIC8vIEFzc3VtcHRpb246IGJ5dGVMZW5ndGgoKSByZXR1cm4gdmFsdWUgaXMgYWx3YXlzIDwga01heExlbmd0aC5cbiAgdmFyIGxlbmd0aCA9IGJ5dGVMZW5ndGgoc3RyaW5nLCBlbmNvZGluZykgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG5cbiAgdGhhdC53cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihvYmplY3QpKSByZXR1cm4gZnJvbUJ1ZmZlcih0aGF0LCBvYmplY3QpXG5cbiAgaWYgKGlzQXJyYXkob2JqZWN0KSkgcmV0dXJuIGZyb21BcnJheSh0aGF0LCBvYmplY3QpXG5cbiAgaWYgKG9iamVjdCA9PSBudWxsKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignbXVzdCBzdGFydCB3aXRoIG51bWJlciwgYnVmZmVyLCBhcnJheSBvciBzdHJpbmcnKVxuICB9XG5cbiAgaWYgKHR5cGVvZiBBcnJheUJ1ZmZlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAob2JqZWN0LmJ1ZmZlciBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgICByZXR1cm4gZnJvbVR5cGVkQXJyYXkodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgICBpZiAob2JqZWN0IGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICAgIHJldHVybiBmcm9tQXJyYXlCdWZmZXIodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgfVxuXG4gIGlmIChvYmplY3QubGVuZ3RoKSByZXR1cm4gZnJvbUFycmF5TGlrZSh0aGF0LCBvYmplY3QpXG5cbiAgcmV0dXJuIGZyb21Kc29uT2JqZWN0KHRoYXQsIG9iamVjdClcbn1cblxuZnVuY3Rpb24gZnJvbUJ1ZmZlciAodGhhdCwgYnVmZmVyKSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGJ1ZmZlci5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICBidWZmZXIuY29weSh0aGF0LCAwLCAwLCBsZW5ndGgpXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheSAodGhhdCwgYXJyYXkpIHtcbiAgdmFyIGxlbmd0aCA9IGNoZWNrZWQoYXJyYXkubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbi8vIER1cGxpY2F0ZSBvZiBmcm9tQXJyYXkoKSB0byBrZWVwIGZyb21BcnJheSgpIG1vbm9tb3JwaGljLlxuZnVuY3Rpb24gZnJvbVR5cGVkQXJyYXkgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIC8vIFRydW5jYXRpbmcgdGhlIGVsZW1lbnRzIGlzIHByb2JhYmx5IG5vdCB3aGF0IHBlb3BsZSBleHBlY3QgZnJvbSB0eXBlZFxuICAvLyBhcnJheXMgd2l0aCBCWVRFU19QRVJfRUxFTUVOVCA+IDEgYnV0IGl0J3MgY29tcGF0aWJsZSB3aXRoIHRoZSBiZWhhdmlvclxuICAvLyBvZiB0aGUgb2xkIEJ1ZmZlciBjb25zdHJ1Y3Rvci5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUJ1ZmZlciAodGhhdCwgYXJyYXkpIHtcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgYXJyYXkuYnl0ZUxlbmd0aFxuICAgIHRoYXQgPSBCdWZmZXIuX2F1Z21lbnQobmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0ID0gZnJvbVR5cGVkQXJyYXkodGhhdCwgbmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUxpa2UgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vLyBEZXNlcmlhbGl6ZSB7IHR5cGU6ICdCdWZmZXInLCBkYXRhOiBbMSwyLDMsLi4uXSB9IGludG8gYSBCdWZmZXIgb2JqZWN0LlxuLy8gUmV0dXJucyBhIHplcm8tbGVuZ3RoIGJ1ZmZlciBmb3IgaW5wdXRzIHRoYXQgZG9uJ3QgY29uZm9ybSB0byB0aGUgc3BlYy5cbmZ1bmN0aW9uIGZyb21Kc29uT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgdmFyIGFycmF5XG4gIHZhciBsZW5ndGggPSAwXG5cbiAgaWYgKG9iamVjdC50eXBlID09PSAnQnVmZmVyJyAmJiBpc0FycmF5KG9iamVjdC5kYXRhKSkge1xuICAgIGFycmF5ID0gb2JqZWN0LmRhdGFcbiAgICBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIH1cbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gIEJ1ZmZlci5wcm90b3R5cGUuX19wcm90b19fID0gVWludDhBcnJheS5wcm90b3R5cGVcbiAgQnVmZmVyLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXlcbn1cblxuZnVuY3Rpb24gYWxsb2NhdGUgKHRoYXQsIGxlbmd0aCkge1xuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAvLyBSZXR1cm4gYW4gYXVnbWVudGVkIGBVaW50OEFycmF5YCBpbnN0YW5jZSwgZm9yIGJlc3QgcGVyZm9ybWFuY2VcbiAgICB0aGF0ID0gQnVmZmVyLl9hdWdtZW50KG5ldyBVaW50OEFycmF5KGxlbmd0aCkpXG4gICAgdGhhdC5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgLy8gRmFsbGJhY2s6IFJldHVybiBhbiBvYmplY3QgaW5zdGFuY2Ugb2YgdGhlIEJ1ZmZlciBjbGFzc1xuICAgIHRoYXQubGVuZ3RoID0gbGVuZ3RoXG4gICAgdGhhdC5faXNCdWZmZXIgPSB0cnVlXG4gIH1cblxuICB2YXIgZnJvbVBvb2wgPSBsZW5ndGggIT09IDAgJiYgbGVuZ3RoIDw9IEJ1ZmZlci5wb29sU2l6ZSA+Pj4gMVxuICBpZiAoZnJvbVBvb2wpIHRoYXQucGFyZW50ID0gcm9vdFBhcmVudFxuXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGNoZWNrZWQgKGxlbmd0aCkge1xuICAvLyBOb3RlOiBjYW5ub3QgdXNlIGBsZW5ndGggPCBrTWF4TGVuZ3RoYCBoZXJlIGJlY2F1c2UgdGhhdCBmYWlscyB3aGVuXG4gIC8vIGxlbmd0aCBpcyBOYU4gKHdoaWNoIGlzIG90aGVyd2lzZSBjb2VyY2VkIHRvIHplcm8uKVxuICBpZiAobGVuZ3RoID49IGtNYXhMZW5ndGgoKSkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIGFsbG9jYXRlIEJ1ZmZlciBsYXJnZXIgdGhhbiBtYXhpbXVtICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICdzaXplOiAweCcgKyBrTWF4TGVuZ3RoKCkudG9TdHJpbmcoMTYpICsgJyBieXRlcycpXG4gIH1cbiAgcmV0dXJuIGxlbmd0aCB8IDBcbn1cblxuZnVuY3Rpb24gU2xvd0J1ZmZlciAoc3ViamVjdCwgZW5jb2RpbmcpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFNsb3dCdWZmZXIpKSByZXR1cm4gbmV3IFNsb3dCdWZmZXIoc3ViamVjdCwgZW5jb2RpbmcpXG5cbiAgdmFyIGJ1ZiA9IG5ldyBCdWZmZXIoc3ViamVjdCwgZW5jb2RpbmcpXG4gIGRlbGV0ZSBidWYucGFyZW50XG4gIHJldHVybiBidWZcbn1cblxuQnVmZmVyLmlzQnVmZmVyID0gZnVuY3Rpb24gaXNCdWZmZXIgKGIpIHtcbiAgcmV0dXJuICEhKGIgIT0gbnVsbCAmJiBiLl9pc0J1ZmZlcilcbn1cblxuQnVmZmVyLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChhLCBiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGEpIHx8ICFCdWZmZXIuaXNCdWZmZXIoYikpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudHMgbXVzdCBiZSBCdWZmZXJzJylcbiAgfVxuXG4gIGlmIChhID09PSBiKSByZXR1cm4gMFxuXG4gIHZhciB4ID0gYS5sZW5ndGhcbiAgdmFyIHkgPSBiLmxlbmd0aFxuXG4gIHZhciBpID0gMFxuICB2YXIgbGVuID0gTWF0aC5taW4oeCwgeSlcbiAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICBpZiAoYVtpXSAhPT0gYltpXSkgYnJlYWtcblxuICAgICsraVxuICB9XG5cbiAgaWYgKGkgIT09IGxlbikge1xuICAgIHggPSBhW2ldXG4gICAgeSA9IGJbaV1cbiAgfVxuXG4gIGlmICh4IDwgeSkgcmV0dXJuIC0xXG4gIGlmICh5IDwgeCkgcmV0dXJuIDFcbiAgcmV0dXJuIDBcbn1cblxuQnVmZmVyLmlzRW5jb2RpbmcgPSBmdW5jdGlvbiBpc0VuY29kaW5nIChlbmNvZGluZykge1xuICBzd2l0Y2ggKFN0cmluZyhlbmNvZGluZykudG9Mb3dlckNhc2UoKSkge1xuICAgIGNhc2UgJ2hleCc6XG4gICAgY2FzZSAndXRmOCc6XG4gICAgY2FzZSAndXRmLTgnOlxuICAgIGNhc2UgJ2FzY2lpJzpcbiAgICBjYXNlICdiaW5hcnknOlxuICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgY2FzZSAncmF3JzpcbiAgICBjYXNlICd1Y3MyJzpcbiAgICBjYXNlICd1Y3MtMic6XG4gICAgY2FzZSAndXRmMTZsZSc6XG4gICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgcmV0dXJuIHRydWVcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuQnVmZmVyLmNvbmNhdCA9IGZ1bmN0aW9uIGNvbmNhdCAobGlzdCwgbGVuZ3RoKSB7XG4gIGlmICghaXNBcnJheShsaXN0KSkgdGhyb3cgbmV3IFR5cGVFcnJvcignbGlzdCBhcmd1bWVudCBtdXN0IGJlIGFuIEFycmF5IG9mIEJ1ZmZlcnMuJylcblxuICBpZiAobGlzdC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcigwKVxuICB9XG5cbiAgdmFyIGlcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbGVuZ3RoID0gMFxuICAgIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBsZW5ndGggKz0gbGlzdFtpXS5sZW5ndGhcbiAgICB9XG4gIH1cblxuICB2YXIgYnVmID0gbmV3IEJ1ZmZlcihsZW5ndGgpXG4gIHZhciBwb3MgPSAwXG4gIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGl0ZW0gPSBsaXN0W2ldXG4gICAgaXRlbS5jb3B5KGJ1ZiwgcG9zKVxuICAgIHBvcyArPSBpdGVtLmxlbmd0aFxuICB9XG4gIHJldHVybiBidWZcbn1cblxuZnVuY3Rpb24gYnl0ZUxlbmd0aCAoc3RyaW5nLCBlbmNvZGluZykge1xuICBpZiAodHlwZW9mIHN0cmluZyAhPT0gJ3N0cmluZycpIHN0cmluZyA9ICcnICsgc3RyaW5nXG5cbiAgdmFyIGxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKGxlbiA9PT0gMCkgcmV0dXJuIDBcblxuICAvLyBVc2UgYSBmb3IgbG9vcCB0byBhdm9pZCByZWN1cnNpb25cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAvLyBEZXByZWNhdGVkXG4gICAgICBjYXNlICdyYXcnOlxuICAgICAgY2FzZSAncmF3cyc6XG4gICAgICAgIHJldHVybiBsZW5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGhcbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiBsZW4gKiAyXG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gbGVuID4+PiAxXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICByZXR1cm4gYmFzZTY0VG9CeXRlcyhzdHJpbmcpLmxlbmd0aFxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSByZXR1cm4gdXRmOFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGggLy8gYXNzdW1lIHV0ZjhcbiAgICAgICAgZW5jb2RpbmcgPSAoJycgKyBlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cbkJ1ZmZlci5ieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aFxuXG4vLyBwcmUtc2V0IGZvciB2YWx1ZXMgdGhhdCBtYXkgZXhpc3QgaW4gdGhlIGZ1dHVyZVxuQnVmZmVyLnByb3RvdHlwZS5sZW5ndGggPSB1bmRlZmluZWRcbkJ1ZmZlci5wcm90b3R5cGUucGFyZW50ID0gdW5kZWZpbmVkXG5cbmZ1bmN0aW9uIHNsb3dUb1N0cmluZyAoZW5jb2RpbmcsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcblxuICBzdGFydCA9IHN0YXJ0IHwgMFxuICBlbmQgPSBlbmQgPT09IHVuZGVmaW5lZCB8fCBlbmQgPT09IEluZmluaXR5ID8gdGhpcy5sZW5ndGggOiBlbmQgfCAwXG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcbiAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKGVuZCA8PSBzdGFydCkgcmV0dXJuICcnXG5cbiAgd2hpbGUgKHRydWUpIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1dGYxNmxlU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKGVuY29kaW5nICsgJycpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9TdHJpbmcgPSBmdW5jdGlvbiB0b1N0cmluZyAoKSB7XG4gIHZhciBsZW5ndGggPSB0aGlzLmxlbmd0aCB8IDBcbiAgaWYgKGxlbmd0aCA9PT0gMCkgcmV0dXJuICcnXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSByZXR1cm4gdXRmOFNsaWNlKHRoaXMsIDAsIGxlbmd0aClcbiAgcmV0dXJuIHNsb3dUb1N0cmluZy5hcHBseSh0aGlzLCBhcmd1bWVudHMpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24gZXF1YWxzIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiB0cnVlXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKSA9PT0gMFxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluc3BlY3QgPSBmdW5jdGlvbiBpbnNwZWN0ICgpIHtcbiAgdmFyIHN0ciA9ICcnXG4gIHZhciBtYXggPSBleHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTXG4gIGlmICh0aGlzLmxlbmd0aCA+IDApIHtcbiAgICBzdHIgPSB0aGlzLnRvU3RyaW5nKCdoZXgnLCAwLCBtYXgpLm1hdGNoKC8uezJ9L2cpLmpvaW4oJyAnKVxuICAgIGlmICh0aGlzLmxlbmd0aCA+IG1heCkgc3RyICs9ICcgLi4uICdcbiAgfVxuICByZXR1cm4gJzxCdWZmZXIgJyArIHN0ciArICc+J1xufVxuXG5CdWZmZXIucHJvdG90eXBlLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiAwXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluZGV4T2YgPSBmdW5jdGlvbiBpbmRleE9mICh2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgaWYgKGJ5dGVPZmZzZXQgPiAweDdmZmZmZmZmKSBieXRlT2Zmc2V0ID0gMHg3ZmZmZmZmZlxuICBlbHNlIGlmIChieXRlT2Zmc2V0IDwgLTB4ODAwMDAwMDApIGJ5dGVPZmZzZXQgPSAtMHg4MDAwMDAwMFxuICBieXRlT2Zmc2V0ID4+PSAwXG5cbiAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gLTFcbiAgaWYgKGJ5dGVPZmZzZXQgPj0gdGhpcy5sZW5ndGgpIHJldHVybiAtMVxuXG4gIC8vIE5lZ2F0aXZlIG9mZnNldHMgc3RhcnQgZnJvbSB0aGUgZW5kIG9mIHRoZSBidWZmZXJcbiAgaWYgKGJ5dGVPZmZzZXQgPCAwKSBieXRlT2Zmc2V0ID0gTWF0aC5tYXgodGhpcy5sZW5ndGggKyBieXRlT2Zmc2V0LCAwKVxuXG4gIGlmICh0eXBlb2YgdmFsID09PSAnc3RyaW5nJykge1xuICAgIGlmICh2YWwubGVuZ3RoID09PSAwKSByZXR1cm4gLTEgLy8gc3BlY2lhbCBjYXNlOiBsb29raW5nIGZvciBlbXB0eSBzdHJpbmcgYWx3YXlzIGZhaWxzXG4gICAgcmV0dXJuIFN0cmluZy5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAoQnVmZmVyLmlzQnVmZmVyKHZhbCkpIHtcbiAgICByZXR1cm4gYXJyYXlJbmRleE9mKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ251bWJlcicpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQgJiYgVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgcmV0dXJuIFVpbnQ4QXJyYXkucHJvdG90eXBlLmluZGV4T2YuY2FsbCh0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gICAgfVxuICAgIHJldHVybiBhcnJheUluZGV4T2YodGhpcywgWyB2YWwgXSwgYnl0ZU9mZnNldClcbiAgfVxuXG4gIGZ1bmN0aW9uIGFycmF5SW5kZXhPZiAoYXJyLCB2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgICB2YXIgZm91bmRJbmRleCA9IC0xXG4gICAgZm9yICh2YXIgaSA9IDA7IGJ5dGVPZmZzZXQgKyBpIDwgYXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoYXJyW2J5dGVPZmZzZXQgKyBpXSA9PT0gdmFsW2ZvdW5kSW5kZXggPT09IC0xID8gMCA6IGkgLSBmb3VuZEluZGV4XSkge1xuICAgICAgICBpZiAoZm91bmRJbmRleCA9PT0gLTEpIGZvdW5kSW5kZXggPSBpXG4gICAgICAgIGlmIChpIC0gZm91bmRJbmRleCArIDEgPT09IHZhbC5sZW5ndGgpIHJldHVybiBieXRlT2Zmc2V0ICsgZm91bmRJbmRleFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZm91bmRJbmRleCA9IC0xXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAtMVxuICB9XG5cbiAgdGhyb3cgbmV3IFR5cGVFcnJvcigndmFsIG11c3QgYmUgc3RyaW5nLCBudW1iZXIgb3IgQnVmZmVyJylcbn1cblxuLy8gYGdldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5nZXQgPSBmdW5jdGlvbiBnZXQgKG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLmdldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMucmVhZFVJbnQ4KG9mZnNldClcbn1cblxuLy8gYHNldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5zZXQgPSBmdW5jdGlvbiBzZXQgKHYsIG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLnNldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMud3JpdGVVSW50OCh2LCBvZmZzZXQpXG59XG5cbmZ1bmN0aW9uIGhleFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgb2Zmc2V0ID0gTnVtYmVyKG9mZnNldCkgfHwgMFxuICB2YXIgcmVtYWluaW5nID0gYnVmLmxlbmd0aCAtIG9mZnNldFxuICBpZiAoIWxlbmd0aCkge1xuICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICB9IGVsc2Uge1xuICAgIGxlbmd0aCA9IE51bWJlcihsZW5ndGgpXG4gICAgaWYgKGxlbmd0aCA+IHJlbWFpbmluZykge1xuICAgICAgbGVuZ3RoID0gcmVtYWluaW5nXG4gICAgfVxuICB9XG5cbiAgLy8gbXVzdCBiZSBhbiBldmVuIG51bWJlciBvZiBkaWdpdHNcbiAgdmFyIHN0ckxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKHN0ckxlbiAlIDIgIT09IDApIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcblxuICBpZiAobGVuZ3RoID4gc3RyTGVuIC8gMikge1xuICAgIGxlbmd0aCA9IHN0ckxlbiAvIDJcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHBhcnNlZCA9IHBhcnNlSW50KHN0cmluZy5zdWJzdHIoaSAqIDIsIDIpLCAxNilcbiAgICBpZiAoaXNOYU4ocGFyc2VkKSkgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGhleCBzdHJpbmcnKVxuICAgIGJ1ZltvZmZzZXQgKyBpXSA9IHBhcnNlZFxuICB9XG4gIHJldHVybiBpXG59XG5cbmZ1bmN0aW9uIHV0ZjhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKHV0ZjhUb0J5dGVzKHN0cmluZywgYnVmLmxlbmd0aCAtIG9mZnNldCksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGFzY2lpV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcihhc2NpaVRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYmluYXJ5V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYXNjaWlXcml0ZShidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGJhc2U2NFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIoYmFzZTY0VG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiB1Y3MyV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcih1dGYxNmxlVG9CeXRlcyhzdHJpbmcsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlID0gZnVuY3Rpb24gd3JpdGUgKHN0cmluZywgb2Zmc2V0LCBsZW5ndGgsIGVuY29kaW5nKSB7XG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcpXG4gIGlmIChvZmZzZXQgPT09IHVuZGVmaW5lZCkge1xuICAgIGVuY29kaW5nID0gJ3V0ZjgnXG4gICAgbGVuZ3RoID0gdGhpcy5sZW5ndGhcbiAgICBvZmZzZXQgPSAwXG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICB9IGVsc2UgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkICYmIHR5cGVvZiBvZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgZW5jb2RpbmcgPSBvZmZzZXRcbiAgICBsZW5ndGggPSB0aGlzLmxlbmd0aFxuICAgIG9mZnNldCA9IDBcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZywgb2Zmc2V0WywgbGVuZ3RoXVssIGVuY29kaW5nXSlcbiAgfSBlbHNlIGlmIChpc0Zpbml0ZShvZmZzZXQpKSB7XG4gICAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICAgIGlmIChpc0Zpbml0ZShsZW5ndGgpKSB7XG4gICAgICBsZW5ndGggPSBsZW5ndGggfCAwXG4gICAgICBpZiAoZW5jb2RpbmcgPT09IHVuZGVmaW5lZCkgZW5jb2RpbmcgPSAndXRmOCdcbiAgICB9IGVsc2Uge1xuICAgICAgZW5jb2RpbmcgPSBsZW5ndGhcbiAgICAgIGxlbmd0aCA9IHVuZGVmaW5lZFxuICAgIH1cbiAgLy8gbGVnYWN5IHdyaXRlKHN0cmluZywgZW5jb2RpbmcsIG9mZnNldCwgbGVuZ3RoKSAtIHJlbW92ZSBpbiB2MC4xM1xuICB9IGVsc2Uge1xuICAgIHZhciBzd2FwID0gZW5jb2RpbmdcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIG9mZnNldCA9IGxlbmd0aCB8IDBcbiAgICBsZW5ndGggPSBzd2FwXG4gIH1cblxuICB2YXIgcmVtYWluaW5nID0gdGhpcy5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkIHx8IGxlbmd0aCA+IHJlbWFpbmluZykgbGVuZ3RoID0gcmVtYWluaW5nXG5cbiAgaWYgKChzdHJpbmcubGVuZ3RoID4gMCAmJiAobGVuZ3RoIDwgMCB8fCBvZmZzZXQgPCAwKSkgfHwgb2Zmc2V0ID4gdGhpcy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignYXR0ZW1wdCB0byB3cml0ZSBvdXRzaWRlIGJ1ZmZlciBib3VuZHMnKVxuICB9XG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcblxuICB2YXIgbG93ZXJlZENhc2UgPSBmYWxzZVxuICBmb3IgKDs7KSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGhleFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgICAgcmV0dXJuIGFzY2lpV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgICAgcmV0dXJuIGJpbmFyeVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIC8vIFdhcm5pbmc6IG1heExlbmd0aCBub3QgdGFrZW4gaW50byBhY2NvdW50IGluIGJhc2U2NFdyaXRlXG4gICAgICAgIHJldHVybiBiYXNlNjRXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gdWNzMldyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgICAgICBlbmNvZGluZyA9ICgnJyArIGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvSlNPTiA9IGZ1bmN0aW9uIHRvSlNPTiAoKSB7XG4gIHJldHVybiB7XG4gICAgdHlwZTogJ0J1ZmZlcicsXG4gICAgZGF0YTogQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodGhpcy5fYXJyIHx8IHRoaXMsIDApXG4gIH1cbn1cblxuZnVuY3Rpb24gYmFzZTY0U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICBpZiAoc3RhcnQgPT09IDAgJiYgZW5kID09PSBidWYubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGJhc2U2NC5mcm9tQnl0ZUFycmF5KGJ1ZilcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmLnNsaWNlKHN0YXJ0LCBlbmQpKVxuICB9XG59XG5cbmZ1bmN0aW9uIHV0ZjhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcbiAgdmFyIHJlcyA9IFtdXG5cbiAgdmFyIGkgPSBzdGFydFxuICB3aGlsZSAoaSA8IGVuZCkge1xuICAgIHZhciBmaXJzdEJ5dGUgPSBidWZbaV1cbiAgICB2YXIgY29kZVBvaW50ID0gbnVsbFxuICAgIHZhciBieXRlc1BlclNlcXVlbmNlID0gKGZpcnN0Qnl0ZSA+IDB4RUYpID8gNFxuICAgICAgOiAoZmlyc3RCeXRlID4gMHhERikgPyAzXG4gICAgICA6IChmaXJzdEJ5dGUgPiAweEJGKSA/IDJcbiAgICAgIDogMVxuXG4gICAgaWYgKGkgKyBieXRlc1BlclNlcXVlbmNlIDw9IGVuZCkge1xuICAgICAgdmFyIHNlY29uZEJ5dGUsIHRoaXJkQnl0ZSwgZm91cnRoQnl0ZSwgdGVtcENvZGVQb2ludFxuXG4gICAgICBzd2l0Y2ggKGJ5dGVzUGVyU2VxdWVuY2UpIHtcbiAgICAgICAgY2FzZSAxOlxuICAgICAgICAgIGlmIChmaXJzdEJ5dGUgPCAweDgwKSB7XG4gICAgICAgICAgICBjb2RlUG9pbnQgPSBmaXJzdEJ5dGVcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHgxRikgPDwgMHg2IHwgKHNlY29uZEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweDdGKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwICYmICh0aGlyZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4QyB8IChzZWNvbmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKHRoaXJkQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0ZGICYmICh0ZW1wQ29kZVBvaW50IDwgMHhEODAwIHx8IHRlbXBDb2RlUG9pbnQgPiAweERGRkYpKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSA0OlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGZvdXJ0aEJ5dGUgPSBidWZbaSArIDNdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwICYmIChmb3VydGhCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHhGKSA8PCAweDEyIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweEMgfCAodGhpcmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKGZvdXJ0aEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweEZGRkYgJiYgdGVtcENvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGNvZGVQb2ludCA9PT0gbnVsbCkge1xuICAgICAgLy8gd2UgZGlkIG5vdCBnZW5lcmF0ZSBhIHZhbGlkIGNvZGVQb2ludCBzbyBpbnNlcnQgYVxuICAgICAgLy8gcmVwbGFjZW1lbnQgY2hhciAoVStGRkZEKSBhbmQgYWR2YW5jZSBvbmx5IDEgYnl0ZVxuICAgICAgY29kZVBvaW50ID0gMHhGRkZEXG4gICAgICBieXRlc1BlclNlcXVlbmNlID0gMVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50ID4gMHhGRkZGKSB7XG4gICAgICAvLyBlbmNvZGUgdG8gdXRmMTYgKHN1cnJvZ2F0ZSBwYWlyIGRhbmNlKVxuICAgICAgY29kZVBvaW50IC09IDB4MTAwMDBcbiAgICAgIHJlcy5wdXNoKGNvZGVQb2ludCA+Pj4gMTAgJiAweDNGRiB8IDB4RDgwMClcbiAgICAgIGNvZGVQb2ludCA9IDB4REMwMCB8IGNvZGVQb2ludCAmIDB4M0ZGXG4gICAgfVxuXG4gICAgcmVzLnB1c2goY29kZVBvaW50KVxuICAgIGkgKz0gYnl0ZXNQZXJTZXF1ZW5jZVxuICB9XG5cbiAgcmV0dXJuIGRlY29kZUNvZGVQb2ludHNBcnJheShyZXMpXG59XG5cbi8vIEJhc2VkIG9uIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzIyNzQ3MjcyLzY4MDc0MiwgdGhlIGJyb3dzZXIgd2l0aFxuLy8gdGhlIGxvd2VzdCBsaW1pdCBpcyBDaHJvbWUsIHdpdGggMHgxMDAwMCBhcmdzLlxuLy8gV2UgZ28gMSBtYWduaXR1ZGUgbGVzcywgZm9yIHNhZmV0eVxudmFyIE1BWF9BUkdVTUVOVFNfTEVOR1RIID0gMHgxMDAwXG5cbmZ1bmN0aW9uIGRlY29kZUNvZGVQb2ludHNBcnJheSAoY29kZVBvaW50cykge1xuICB2YXIgbGVuID0gY29kZVBvaW50cy5sZW5ndGhcbiAgaWYgKGxlbiA8PSBNQVhfQVJHVU1FTlRTX0xFTkdUSCkge1xuICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFN0cmluZywgY29kZVBvaW50cykgLy8gYXZvaWQgZXh0cmEgc2xpY2UoKVxuICB9XG5cbiAgLy8gRGVjb2RlIGluIGNodW5rcyB0byBhdm9pZCBcImNhbGwgc3RhY2sgc2l6ZSBleGNlZWRlZFwiLlxuICB2YXIgcmVzID0gJydcbiAgdmFyIGkgPSAwXG4gIHdoaWxlIChpIDwgbGVuKSB7XG4gICAgcmVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoXG4gICAgICBTdHJpbmcsXG4gICAgICBjb2RlUG9pbnRzLnNsaWNlKGksIGkgKz0gTUFYX0FSR1VNRU5UU19MRU5HVEgpXG4gICAgKVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0gJiAweDdGKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gYmluYXJ5U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgcmV0ID0gJydcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgcmV0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnVmW2ldKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gaGV4U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gYnVmLmxlbmd0aFxuXG4gIGlmICghc3RhcnQgfHwgc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgfHwgZW5kIDwgMCB8fCBlbmQgPiBsZW4pIGVuZCA9IGxlblxuXG4gIHZhciBvdXQgPSAnJ1xuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIG91dCArPSB0b0hleChidWZbaV0pXG4gIH1cbiAgcmV0dXJuIG91dFxufVxuXG5mdW5jdGlvbiB1dGYxNmxlU2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgYnl0ZXMgPSBidWYuc2xpY2Uoc3RhcnQsIGVuZClcbiAgdmFyIHJlcyA9ICcnXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShieXRlc1tpXSArIGJ5dGVzW2kgKyAxXSAqIDI1NilcbiAgfVxuICByZXR1cm4gcmVzXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuc2xpY2UgPSBmdW5jdGlvbiBzbGljZSAoc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gdGhpcy5sZW5ndGhcbiAgc3RhcnQgPSB+fnN0YXJ0XG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkID8gbGVuIDogfn5lbmRcblxuICBpZiAoc3RhcnQgPCAwKSB7XG4gICAgc3RhcnQgKz0gbGVuXG4gICAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIH0gZWxzZSBpZiAoc3RhcnQgPiBsZW4pIHtcbiAgICBzdGFydCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IDApIHtcbiAgICBlbmQgKz0gbGVuXG4gICAgaWYgKGVuZCA8IDApIGVuZCA9IDBcbiAgfSBlbHNlIGlmIChlbmQgPiBsZW4pIHtcbiAgICBlbmQgPSBsZW5cbiAgfVxuXG4gIGlmIChlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICB2YXIgbmV3QnVmXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIG5ld0J1ZiA9IEJ1ZmZlci5fYXVnbWVudCh0aGlzLnN1YmFycmF5KHN0YXJ0LCBlbmQpKVxuICB9IGVsc2Uge1xuICAgIHZhciBzbGljZUxlbiA9IGVuZCAtIHN0YXJ0XG4gICAgbmV3QnVmID0gbmV3IEJ1ZmZlcihzbGljZUxlbiwgdW5kZWZpbmVkKVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2xpY2VMZW47IGkrKykge1xuICAgICAgbmV3QnVmW2ldID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9XG5cbiAgaWYgKG5ld0J1Zi5sZW5ndGgpIG5ld0J1Zi5wYXJlbnQgPSB0aGlzLnBhcmVudCB8fCB0aGlzXG5cbiAgcmV0dXJuIG5ld0J1ZlxufVxuXG4vKlxuICogTmVlZCB0byBtYWtlIHN1cmUgdGhhdCBidWZmZXIgaXNuJ3QgdHJ5aW5nIHRvIHdyaXRlIG91dCBvZiBib3VuZHMuXG4gKi9cbmZ1bmN0aW9uIGNoZWNrT2Zmc2V0IChvZmZzZXQsIGV4dCwgbGVuZ3RoKSB7XG4gIGlmICgob2Zmc2V0ICUgMSkgIT09IDAgfHwgb2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ29mZnNldCBpcyBub3QgdWludCcpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBsZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdUcnlpbmcgdG8gYWNjZXNzIGJleW9uZCBidWZmZXIgbGVuZ3RoJylcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludExFID0gZnVuY3Rpb24gcmVhZFVJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludEJFID0gZnVuY3Rpb24gcmVhZFVJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcbiAgfVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIC0tYnl0ZUxlbmd0aF1cbiAgdmFyIG11bCA9IDFcbiAgd2hpbGUgKGJ5dGVMZW5ndGggPiAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50OCA9IGZ1bmN0aW9uIHJlYWRVSW50OCAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDEsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gdGhpc1tvZmZzZXRdXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkxFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MTZCRSA9IGZ1bmN0aW9uIHJlYWRVSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCA4KSB8IHRoaXNbb2Zmc2V0ICsgMV1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyTEUgPSBmdW5jdGlvbiByZWFkVUludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKCh0aGlzW29mZnNldF0pIHxcbiAgICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAgICh0aGlzW29mZnNldCArIDJdIDw8IDE2KSkgK1xuICAgICAgKHRoaXNbb2Zmc2V0ICsgM10gKiAweDEwMDAwMDApXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQzMkJFID0gZnVuY3Rpb24gcmVhZFVJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gKiAweDEwMDAwMDApICtcbiAgICAoKHRoaXNbb2Zmc2V0ICsgMV0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCA4KSB8XG4gICAgdGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50TEUgPSBmdW5jdGlvbiByZWFkSW50TEUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIGldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50QkUgPSBmdW5jdGlvbiByZWFkSW50QkUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgaSA9IGJ5dGVMZW5ndGhcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1pXVxuICB3aGlsZSAoaSA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50OCA9IGZ1bmN0aW9uIHJlYWRJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIGlmICghKHRoaXNbb2Zmc2V0XSAmIDB4ODApKSByZXR1cm4gKHRoaXNbb2Zmc2V0XSlcbiAgcmV0dXJuICgoMHhmZiAtIHRoaXNbb2Zmc2V0XSArIDEpICogLTEpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2TEUgPSBmdW5jdGlvbiByZWFkSW50MTZMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdIHwgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQxNkJFID0gZnVuY3Rpb24gcmVhZEludDE2QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgMV0gfCAodGhpc1tvZmZzZXRdIDw8IDgpXG4gIHJldHVybiAodmFsICYgMHg4MDAwKSA/IHZhbCB8IDB4RkZGRjAwMDAgOiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0pIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSA8PCAyNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJCRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gPDwgMjQpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRMRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdExFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRCRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdEJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCBmYWxzZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUxFID0gZnVuY3Rpb24gcmVhZERvdWJsZUxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgOCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCA1MiwgOClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlQkUgPSBmdW5jdGlvbiByZWFkRG91YmxlQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCA1MiwgOClcbn1cblxuZnVuY3Rpb24gY2hlY2tJbnQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihidWYpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdidWZmZXIgbXVzdCBiZSBhIEJ1ZmZlciBpbnN0YW5jZScpXG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3ZhbHVlIGlzIG91dCBvZiBib3VuZHMnKVxuICBpZiAob2Zmc2V0ICsgZXh0ID4gYnVmLmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB0aGlzW29mZnNldF0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50QkUgPSBmdW5jdGlvbiB3cml0ZVVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aCAtIDFcbiAgdmFyIG11bCA9IDFcbiAgdGhpc1tvZmZzZXQgKyBpXSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoLS1pID49IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50OCA9IGZ1bmN0aW9uIHdyaXRlVUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHhmZiwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkgdmFsdWUgPSBNYXRoLmZsb29yKHZhbHVlKVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQxNiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmYgKyB2YWx1ZSArIDFcbiAgZm9yICh2YXIgaSA9IDAsIGogPSBNYXRoLm1pbihidWYubGVuZ3RoIC0gb2Zmc2V0LCAyKTsgaSA8IGo7IGkrKykge1xuICAgIGJ1ZltvZmZzZXQgKyBpXSA9ICh2YWx1ZSAmICgweGZmIDw8ICg4ICogKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkpKSkgPj4+XG4gICAgICAobGl0dGxlRW5kaWFuID8gaSA6IDEgLSBpKSAqIDhcbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDE2TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4ZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQzMiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgNCk7IGkgPCBqOyBpKyspIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgPj4+IChsaXR0bGVFbmRpYW4gPyBpIDogMyAtIGkpICogOCkgJiAweGZmXG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDMyQkUgPSBmdW5jdGlvbiB3cml0ZVVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4ZmZmZmZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50TEUgPSBmdW5jdGlvbiB3cml0ZUludExFICh2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbGltaXQgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCAtIDEpXG5cbiAgICBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBsaW1pdCAtIDEsIC1saW1pdClcbiAgfVxuXG4gIHZhciBpID0gMFxuICB2YXIgbXVsID0gMVxuICB2YXIgc3ViID0gdmFsdWUgPCAwID8gMSA6IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludEJFID0gZnVuY3Rpb24gd3JpdGVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSB2YWx1ZSA8IDAgPyAxIDogMFxuICB0aGlzW29mZnNldCArIGldID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgtLWkgPj0gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAoKHZhbHVlIC8gbXVsKSA+PiAwKSAtIHN1YiAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQ4ID0gZnVuY3Rpb24gd3JpdGVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4N2YsIC0weDgwKVxuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB2YWx1ZSA9IE1hdGguZmxvb3IodmFsdWUpXG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZiArIHZhbHVlICsgMVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MTZMRSA9IGZ1bmN0aW9uIHdyaXRlSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweDdmZmYsIC0weDgwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MzJCRSA9IGZ1bmN0aW9uIHdyaXRlSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweDdmZmZmZmZmLCAtMHg4MDAwMDAwMClcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5mdW5jdGlvbiBjaGVja0lFRUU3NTQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAodmFsdWUgPiBtYXggfHwgdmFsdWUgPCBtaW4pIHRocm93IG5ldyBSYW5nZUVycm9yKCd2YWx1ZSBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxuICBpZiAob2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRmxvYXQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgNCwgMy40MDI4MjM0NjYzODUyODg2ZSszOCwgLTMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgMjMsIDQpXG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdExFID0gZnVuY3Rpb24gd3JpdGVGbG9hdExFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUZsb2F0QkUgPSBmdW5jdGlvbiB3cml0ZUZsb2F0QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZUZsb2F0KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuZnVuY3Rpb24gd3JpdGVEb3VibGUgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgOCwgMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgsIC0xLjc5NzY5MzEzNDg2MjMxNTdFKzMwOClcbiAgfVxuICBpZWVlNzU0LndyaXRlKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCA1MiwgOClcbiAgcmV0dXJuIG9mZnNldCArIDhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUxFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUsIG5vQXNzZXJ0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRG91YmxlQkUgPSBmdW5jdGlvbiB3cml0ZURvdWJsZUJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVEb3VibGUodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UsIG5vQXNzZXJ0KVxufVxuXG4vLyBjb3B5KHRhcmdldEJ1ZmZlciwgdGFyZ2V0U3RhcnQ9MCwgc291cmNlU3RhcnQ9MCwgc291cmNlRW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmNvcHkgPSBmdW5jdGlvbiBjb3B5ICh0YXJnZXQsIHRhcmdldFN0YXJ0LCBzdGFydCwgZW5kKSB7XG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCAmJiBlbmQgIT09IDApIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmICh0YXJnZXRTdGFydCA+PSB0YXJnZXQubGVuZ3RoKSB0YXJnZXRTdGFydCA9IHRhcmdldC5sZW5ndGhcbiAgaWYgKCF0YXJnZXRTdGFydCkgdGFyZ2V0U3RhcnQgPSAwXG4gIGlmIChlbmQgPiAwICYmIGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIC8vIENvcHkgMCBieXRlczsgd2UncmUgZG9uZVxuICBpZiAoZW5kID09PSBzdGFydCkgcmV0dXJuIDBcbiAgaWYgKHRhcmdldC5sZW5ndGggPT09IDAgfHwgdGhpcy5sZW5ndGggPT09IDApIHJldHVybiAwXG5cbiAgLy8gRmF0YWwgZXJyb3IgY29uZGl0aW9uc1xuICBpZiAodGFyZ2V0U3RhcnQgPCAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3RhcmdldFN0YXJ0IG91dCBvZiBib3VuZHMnKVxuICB9XG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VFbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgLy8gQXJlIHdlIG9vYj9cbiAgaWYgKGVuZCA+IHRoaXMubGVuZ3RoKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0IDwgZW5kIC0gc3RhcnQpIHtcbiAgICBlbmQgPSB0YXJnZXQubGVuZ3RoIC0gdGFyZ2V0U3RhcnQgKyBzdGFydFxuICB9XG5cbiAgdmFyIGxlbiA9IGVuZCAtIHN0YXJ0XG4gIHZhciBpXG5cbiAgaWYgKHRoaXMgPT09IHRhcmdldCAmJiBzdGFydCA8IHRhcmdldFN0YXJ0ICYmIHRhcmdldFN0YXJ0IDwgZW5kKSB7XG4gICAgLy8gZGVzY2VuZGluZyBjb3B5IGZyb20gZW5kXG4gICAgZm9yIChpID0gbGVuIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2UgaWYgKGxlbiA8IDEwMDAgfHwgIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gYXNjZW5kaW5nIGNvcHkgZnJvbSBzdGFydFxuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgdGFyZ2V0W2kgKyB0YXJnZXRTdGFydF0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGFyZ2V0Ll9zZXQodGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLCB0YXJnZXRTdGFydClcbiAgfVxuXG4gIHJldHVybiBsZW5cbn1cblxuLy8gZmlsbCh2YWx1ZSwgc3RhcnQ9MCwgZW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmZpbGwgPSBmdW5jdGlvbiBmaWxsICh2YWx1ZSwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXZhbHVlKSB2YWx1ZSA9IDBcbiAgaWYgKCFzdGFydCkgc3RhcnQgPSAwXG4gIGlmICghZW5kKSBlbmQgPSB0aGlzLmxlbmd0aFxuXG4gIGlmIChlbmQgPCBzdGFydCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2VuZCA8IHN0YXJ0JylcblxuICAvLyBGaWxsIDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVyblxuICBpZiAodGhpcy5sZW5ndGggPT09IDApIHJldHVyblxuXG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDAgfHwgZW5kID4gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdlbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgdmFyIGlcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICBmb3IgKGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgICB0aGlzW2ldID0gdmFsdWVcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFyIGJ5dGVzID0gdXRmOFRvQnl0ZXModmFsdWUudG9TdHJpbmcoKSlcbiAgICB2YXIgbGVuID0gYnl0ZXMubGVuZ3RoXG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdGhpc1tpXSA9IGJ5dGVzW2kgJSBsZW5dXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXNcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IGBBcnJheUJ1ZmZlcmAgd2l0aCB0aGUgKmNvcGllZCogbWVtb3J5IG9mIHRoZSBidWZmZXIgaW5zdGFuY2UuXG4gKiBBZGRlZCBpbiBOb2RlIDAuMTIuIE9ubHkgYXZhaWxhYmxlIGluIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCBBcnJheUJ1ZmZlci5cbiAqL1xuQnVmZmVyLnByb3RvdHlwZS50b0FycmF5QnVmZmVyID0gZnVuY3Rpb24gdG9BcnJheUJ1ZmZlciAoKSB7XG4gIGlmICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAgIHJldHVybiAobmV3IEJ1ZmZlcih0aGlzKSkuYnVmZmVyXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBidWYgPSBuZXcgVWludDhBcnJheSh0aGlzLmxlbmd0aClcbiAgICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBidWYubGVuZ3RoOyBpIDwgbGVuOyBpICs9IDEpIHtcbiAgICAgICAgYnVmW2ldID0gdGhpc1tpXVxuICAgICAgfVxuICAgICAgcmV0dXJuIGJ1Zi5idWZmZXJcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQnVmZmVyLnRvQXJyYXlCdWZmZXIgbm90IHN1cHBvcnRlZCBpbiB0aGlzIGJyb3dzZXInKVxuICB9XG59XG5cbi8vIEhFTFBFUiBGVU5DVElPTlNcbi8vID09PT09PT09PT09PT09PT1cblxudmFyIEJQID0gQnVmZmVyLnByb3RvdHlwZVxuXG4vKipcbiAqIEF1Z21lbnQgYSBVaW50OEFycmF5ICppbnN0YW5jZSogKG5vdCB0aGUgVWludDhBcnJheSBjbGFzcyEpIHdpdGggQnVmZmVyIG1ldGhvZHNcbiAqL1xuQnVmZmVyLl9hdWdtZW50ID0gZnVuY3Rpb24gX2F1Z21lbnQgKGFycikge1xuICBhcnIuY29uc3RydWN0b3IgPSBCdWZmZXJcbiAgYXJyLl9pc0J1ZmZlciA9IHRydWVcblxuICAvLyBzYXZlIHJlZmVyZW5jZSB0byBvcmlnaW5hbCBVaW50OEFycmF5IHNldCBtZXRob2QgYmVmb3JlIG92ZXJ3cml0aW5nXG4gIGFyci5fc2V0ID0gYXJyLnNldFxuXG4gIC8vIGRlcHJlY2F0ZWRcbiAgYXJyLmdldCA9IEJQLmdldFxuICBhcnIuc2V0ID0gQlAuc2V0XG5cbiAgYXJyLndyaXRlID0gQlAud3JpdGVcbiAgYXJyLnRvU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvTG9jYWxlU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvSlNPTiA9IEJQLnRvSlNPTlxuICBhcnIuZXF1YWxzID0gQlAuZXF1YWxzXG4gIGFyci5jb21wYXJlID0gQlAuY29tcGFyZVxuICBhcnIuaW5kZXhPZiA9IEJQLmluZGV4T2ZcbiAgYXJyLmNvcHkgPSBCUC5jb3B5XG4gIGFyci5zbGljZSA9IEJQLnNsaWNlXG4gIGFyci5yZWFkVUludExFID0gQlAucmVhZFVJbnRMRVxuICBhcnIucmVhZFVJbnRCRSA9IEJQLnJlYWRVSW50QkVcbiAgYXJyLnJlYWRVSW50OCA9IEJQLnJlYWRVSW50OFxuICBhcnIucmVhZFVJbnQxNkxFID0gQlAucmVhZFVJbnQxNkxFXG4gIGFyci5yZWFkVUludDE2QkUgPSBCUC5yZWFkVUludDE2QkVcbiAgYXJyLnJlYWRVSW50MzJMRSA9IEJQLnJlYWRVSW50MzJMRVxuICBhcnIucmVhZFVJbnQzMkJFID0gQlAucmVhZFVJbnQzMkJFXG4gIGFyci5yZWFkSW50TEUgPSBCUC5yZWFkSW50TEVcbiAgYXJyLnJlYWRJbnRCRSA9IEJQLnJlYWRJbnRCRVxuICBhcnIucmVhZEludDggPSBCUC5yZWFkSW50OFxuICBhcnIucmVhZEludDE2TEUgPSBCUC5yZWFkSW50MTZMRVxuICBhcnIucmVhZEludDE2QkUgPSBCUC5yZWFkSW50MTZCRVxuICBhcnIucmVhZEludDMyTEUgPSBCUC5yZWFkSW50MzJMRVxuICBhcnIucmVhZEludDMyQkUgPSBCUC5yZWFkSW50MzJCRVxuICBhcnIucmVhZEZsb2F0TEUgPSBCUC5yZWFkRmxvYXRMRVxuICBhcnIucmVhZEZsb2F0QkUgPSBCUC5yZWFkRmxvYXRCRVxuICBhcnIucmVhZERvdWJsZUxFID0gQlAucmVhZERvdWJsZUxFXG4gIGFyci5yZWFkRG91YmxlQkUgPSBCUC5yZWFkRG91YmxlQkVcbiAgYXJyLndyaXRlVUludDggPSBCUC53cml0ZVVJbnQ4XG4gIGFyci53cml0ZVVJbnRMRSA9IEJQLndyaXRlVUludExFXG4gIGFyci53cml0ZVVJbnRCRSA9IEJQLndyaXRlVUludEJFXG4gIGFyci53cml0ZVVJbnQxNkxFID0gQlAud3JpdGVVSW50MTZMRVxuICBhcnIud3JpdGVVSW50MTZCRSA9IEJQLndyaXRlVUludDE2QkVcbiAgYXJyLndyaXRlVUludDMyTEUgPSBCUC53cml0ZVVJbnQzMkxFXG4gIGFyci53cml0ZVVJbnQzMkJFID0gQlAud3JpdGVVSW50MzJCRVxuICBhcnIud3JpdGVJbnRMRSA9IEJQLndyaXRlSW50TEVcbiAgYXJyLndyaXRlSW50QkUgPSBCUC53cml0ZUludEJFXG4gIGFyci53cml0ZUludDggPSBCUC53cml0ZUludDhcbiAgYXJyLndyaXRlSW50MTZMRSA9IEJQLndyaXRlSW50MTZMRVxuICBhcnIud3JpdGVJbnQxNkJFID0gQlAud3JpdGVJbnQxNkJFXG4gIGFyci53cml0ZUludDMyTEUgPSBCUC53cml0ZUludDMyTEVcbiAgYXJyLndyaXRlSW50MzJCRSA9IEJQLndyaXRlSW50MzJCRVxuICBhcnIud3JpdGVGbG9hdExFID0gQlAud3JpdGVGbG9hdExFXG4gIGFyci53cml0ZUZsb2F0QkUgPSBCUC53cml0ZUZsb2F0QkVcbiAgYXJyLndyaXRlRG91YmxlTEUgPSBCUC53cml0ZURvdWJsZUxFXG4gIGFyci53cml0ZURvdWJsZUJFID0gQlAud3JpdGVEb3VibGVCRVxuICBhcnIuZmlsbCA9IEJQLmZpbGxcbiAgYXJyLmluc3BlY3QgPSBCUC5pbnNwZWN0XG4gIGFyci50b0FycmF5QnVmZmVyID0gQlAudG9BcnJheUJ1ZmZlclxuXG4gIHJldHVybiBhcnJcbn1cblxudmFyIElOVkFMSURfQkFTRTY0X1JFID0gL1teK1xcLzAtOUEtWmEtei1fXS9nXG5cbmZ1bmN0aW9uIGJhc2U2NGNsZWFuIChzdHIpIHtcbiAgLy8gTm9kZSBzdHJpcHMgb3V0IGludmFsaWQgY2hhcmFjdGVycyBsaWtlIFxcbiBhbmQgXFx0IGZyb20gdGhlIHN0cmluZywgYmFzZTY0LWpzIGRvZXMgbm90XG4gIHN0ciA9IHN0cmluZ3RyaW0oc3RyKS5yZXBsYWNlKElOVkFMSURfQkFTRTY0X1JFLCAnJylcbiAgLy8gTm9kZSBjb252ZXJ0cyBzdHJpbmdzIHdpdGggbGVuZ3RoIDwgMiB0byAnJ1xuICBpZiAoc3RyLmxlbmd0aCA8IDIpIHJldHVybiAnJ1xuICAvLyBOb2RlIGFsbG93cyBmb3Igbm9uLXBhZGRlZCBiYXNlNjQgc3RyaW5ncyAobWlzc2luZyB0cmFpbGluZyA9PT0pLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgd2hpbGUgKHN0ci5sZW5ndGggJSA0ICE9PSAwKSB7XG4gICAgc3RyID0gc3RyICsgJz0nXG4gIH1cbiAgcmV0dXJuIHN0clxufVxuXG5mdW5jdGlvbiBzdHJpbmd0cmltIChzdHIpIHtcbiAgaWYgKHN0ci50cmltKSByZXR1cm4gc3RyLnRyaW0oKVxuICByZXR1cm4gc3RyLnJlcGxhY2UoL15cXHMrfFxccyskL2csICcnKVxufVxuXG5mdW5jdGlvbiB0b0hleCAobikge1xuICBpZiAobiA8IDE2KSByZXR1cm4gJzAnICsgbi50b1N0cmluZygxNilcbiAgcmV0dXJuIG4udG9TdHJpbmcoMTYpXG59XG5cbmZ1bmN0aW9uIHV0ZjhUb0J5dGVzIChzdHJpbmcsIHVuaXRzKSB7XG4gIHVuaXRzID0gdW5pdHMgfHwgSW5maW5pdHlcbiAgdmFyIGNvZGVQb2ludFxuICB2YXIgbGVuZ3RoID0gc3RyaW5nLmxlbmd0aFxuICB2YXIgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcbiAgdmFyIGJ5dGVzID0gW11cblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgY29kZVBvaW50ID0gc3RyaW5nLmNoYXJDb2RlQXQoaSlcblxuICAgIC8vIGlzIHN1cnJvZ2F0ZSBjb21wb25lbnRcbiAgICBpZiAoY29kZVBvaW50ID4gMHhEN0ZGICYmIGNvZGVQb2ludCA8IDB4RTAwMCkge1xuICAgICAgLy8gbGFzdCBjaGFyIHdhcyBhIGxlYWRcbiAgICAgIGlmICghbGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgICAvLyBubyBsZWFkIHlldFxuICAgICAgICBpZiAoY29kZVBvaW50ID4gMHhEQkZGKSB7XG4gICAgICAgICAgLy8gdW5leHBlY3RlZCB0cmFpbFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH0gZWxzZSBpZiAoaSArIDEgPT09IGxlbmd0aCkge1xuICAgICAgICAgIC8vIHVucGFpcmVkIGxlYWRcbiAgICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gdmFsaWQgbGVhZFxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG5cbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gMiBsZWFkcyBpbiBhIHJvd1xuICAgICAgaWYgKGNvZGVQb2ludCA8IDB4REMwMCkge1xuICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgbGVhZFN1cnJvZ2F0ZSA9IGNvZGVQb2ludFxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyB2YWxpZCBzdXJyb2dhdGUgcGFpclxuICAgICAgY29kZVBvaW50ID0gKGxlYWRTdXJyb2dhdGUgLSAweEQ4MDAgPDwgMTAgfCBjb2RlUG9pbnQgLSAweERDMDApICsgMHgxMDAwMFxuICAgIH0gZWxzZSBpZiAobGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgLy8gdmFsaWQgYm1wIGNoYXIsIGJ1dCBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgfVxuXG4gICAgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcblxuICAgIC8vIGVuY29kZSB1dGY4XG4gICAgaWYgKGNvZGVQb2ludCA8IDB4ODApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMSkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChjb2RlUG9pbnQpXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDgwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAyKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2IHwgMHhDMCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMykgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyB8IDB4RTAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDQpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDEyIHwgMHhGMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2ICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjb2RlIHBvaW50JylcbiAgICB9XG4gIH1cblxuICByZXR1cm4gYnl0ZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlUb0J5dGVzIChzdHIpIHtcbiAgdmFyIGJ5dGVBcnJheSA9IFtdXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgLy8gTm9kZSdzIGNvZGUgc2VlbXMgdG8gYmUgZG9pbmcgdGhpcyBhbmQgbm90ICYgMHg3Ri4uXG4gICAgYnl0ZUFycmF5LnB1c2goc3RyLmNoYXJDb2RlQXQoaSkgJiAweEZGKVxuICB9XG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gdXRmMTZsZVRvQnl0ZXMgKHN0ciwgdW5pdHMpIHtcbiAgdmFyIGMsIGhpLCBsb1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcblxuICAgIGMgPSBzdHIuY2hhckNvZGVBdChpKVxuICAgIGhpID0gYyA+PiA4XG4gICAgbG8gPSBjICUgMjU2XG4gICAgYnl0ZUFycmF5LnB1c2gobG8pXG4gICAgYnl0ZUFycmF5LnB1c2goaGkpXG4gIH1cblxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIGJhc2U2NFRvQnl0ZXMgKHN0cikge1xuICByZXR1cm4gYmFzZTY0LnRvQnl0ZUFycmF5KGJhc2U2NGNsZWFuKHN0cikpXG59XG5cbmZ1bmN0aW9uIGJsaXRCdWZmZXIgKHNyYywgZHN0LCBvZmZzZXQsIGxlbmd0aCkge1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKChpICsgb2Zmc2V0ID49IGRzdC5sZW5ndGgpIHx8IChpID49IHNyYy5sZW5ndGgpKSBicmVha1xuICAgIGRzdFtpICsgb2Zmc2V0XSA9IHNyY1tpXVxuICB9XG4gIHJldHVybiBpXG59XG4iLCJ2YXIgbG9va3VwID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky8nO1xuXG47KGZ1bmN0aW9uIChleHBvcnRzKSB7XG5cdCd1c2Ugc3RyaWN0JztcblxuICB2YXIgQXJyID0gKHR5cGVvZiBVaW50OEFycmF5ICE9PSAndW5kZWZpbmVkJylcbiAgICA/IFVpbnQ4QXJyYXlcbiAgICA6IEFycmF5XG5cblx0dmFyIFBMVVMgICA9ICcrJy5jaGFyQ29kZUF0KDApXG5cdHZhciBTTEFTSCAgPSAnLycuY2hhckNvZGVBdCgwKVxuXHR2YXIgTlVNQkVSID0gJzAnLmNoYXJDb2RlQXQoMClcblx0dmFyIExPV0VSICA9ICdhJy5jaGFyQ29kZUF0KDApXG5cdHZhciBVUFBFUiAgPSAnQScuY2hhckNvZGVBdCgwKVxuXHR2YXIgUExVU19VUkxfU0FGRSA9ICctJy5jaGFyQ29kZUF0KDApXG5cdHZhciBTTEFTSF9VUkxfU0FGRSA9ICdfJy5jaGFyQ29kZUF0KDApXG5cblx0ZnVuY3Rpb24gZGVjb2RlIChlbHQpIHtcblx0XHR2YXIgY29kZSA9IGVsdC5jaGFyQ29kZUF0KDApXG5cdFx0aWYgKGNvZGUgPT09IFBMVVMgfHxcblx0XHQgICAgY29kZSA9PT0gUExVU19VUkxfU0FGRSlcblx0XHRcdHJldHVybiA2MiAvLyAnKydcblx0XHRpZiAoY29kZSA9PT0gU0xBU0ggfHxcblx0XHQgICAgY29kZSA9PT0gU0xBU0hfVVJMX1NBRkUpXG5cdFx0XHRyZXR1cm4gNjMgLy8gJy8nXG5cdFx0aWYgKGNvZGUgPCBOVU1CRVIpXG5cdFx0XHRyZXR1cm4gLTEgLy9ubyBtYXRjaFxuXHRcdGlmIChjb2RlIDwgTlVNQkVSICsgMTApXG5cdFx0XHRyZXR1cm4gY29kZSAtIE5VTUJFUiArIDI2ICsgMjZcblx0XHRpZiAoY29kZSA8IFVQUEVSICsgMjYpXG5cdFx0XHRyZXR1cm4gY29kZSAtIFVQUEVSXG5cdFx0aWYgKGNvZGUgPCBMT1dFUiArIDI2KVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBMT1dFUiArIDI2XG5cdH1cblxuXHRmdW5jdGlvbiBiNjRUb0J5dGVBcnJheSAoYjY0KSB7XG5cdFx0dmFyIGksIGosIGwsIHRtcCwgcGxhY2VIb2xkZXJzLCBhcnJcblxuXHRcdGlmIChiNjQubGVuZ3RoICUgNCA+IDApIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzdHJpbmcuIExlbmd0aCBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgNCcpXG5cdFx0fVxuXG5cdFx0Ly8gdGhlIG51bWJlciBvZiBlcXVhbCBzaWducyAocGxhY2UgaG9sZGVycylcblx0XHQvLyBpZiB0aGVyZSBhcmUgdHdvIHBsYWNlaG9sZGVycywgdGhhbiB0aGUgdHdvIGNoYXJhY3RlcnMgYmVmb3JlIGl0XG5cdFx0Ly8gcmVwcmVzZW50IG9uZSBieXRlXG5cdFx0Ly8gaWYgdGhlcmUgaXMgb25seSBvbmUsIHRoZW4gdGhlIHRocmVlIGNoYXJhY3RlcnMgYmVmb3JlIGl0IHJlcHJlc2VudCAyIGJ5dGVzXG5cdFx0Ly8gdGhpcyBpcyBqdXN0IGEgY2hlYXAgaGFjayB0byBub3QgZG8gaW5kZXhPZiB0d2ljZVxuXHRcdHZhciBsZW4gPSBiNjQubGVuZ3RoXG5cdFx0cGxhY2VIb2xkZXJzID0gJz0nID09PSBiNjQuY2hhckF0KGxlbiAtIDIpID8gMiA6ICc9JyA9PT0gYjY0LmNoYXJBdChsZW4gLSAxKSA/IDEgOiAwXG5cblx0XHQvLyBiYXNlNjQgaXMgNC8zICsgdXAgdG8gdHdvIGNoYXJhY3RlcnMgb2YgdGhlIG9yaWdpbmFsIGRhdGFcblx0XHRhcnIgPSBuZXcgQXJyKGI2NC5sZW5ndGggKiAzIC8gNCAtIHBsYWNlSG9sZGVycylcblxuXHRcdC8vIGlmIHRoZXJlIGFyZSBwbGFjZWhvbGRlcnMsIG9ubHkgZ2V0IHVwIHRvIHRoZSBsYXN0IGNvbXBsZXRlIDQgY2hhcnNcblx0XHRsID0gcGxhY2VIb2xkZXJzID4gMCA/IGI2NC5sZW5ndGggLSA0IDogYjY0Lmxlbmd0aFxuXG5cdFx0dmFyIEwgPSAwXG5cblx0XHRmdW5jdGlvbiBwdXNoICh2KSB7XG5cdFx0XHRhcnJbTCsrXSA9IHZcblx0XHR9XG5cblx0XHRmb3IgKGkgPSAwLCBqID0gMDsgaSA8IGw7IGkgKz0gNCwgaiArPSAzKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDE4KSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDEyKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMikpIDw8IDYpIHwgZGVjb2RlKGI2NC5jaGFyQXQoaSArIDMpKVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwMDApID4+IDE2KVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwKSA+PiA4KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH1cblxuXHRcdGlmIChwbGFjZUhvbGRlcnMgPT09IDIpIHtcblx0XHRcdHRtcCA9IChkZWNvZGUoYjY0LmNoYXJBdChpKSkgPDwgMikgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA+PiA0KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH0gZWxzZSBpZiAocGxhY2VIb2xkZXJzID09PSAxKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDEwKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDQpIHwgKGRlY29kZShiNjQuY2hhckF0KGkgKyAyKSkgPj4gMilcblx0XHRcdHB1c2goKHRtcCA+PiA4KSAmIDB4RkYpXG5cdFx0XHRwdXNoKHRtcCAmIDB4RkYpXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGFyclxuXHR9XG5cblx0ZnVuY3Rpb24gdWludDhUb0Jhc2U2NCAodWludDgpIHtcblx0XHR2YXIgaSxcblx0XHRcdGV4dHJhQnl0ZXMgPSB1aW50OC5sZW5ndGggJSAzLCAvLyBpZiB3ZSBoYXZlIDEgYnl0ZSBsZWZ0LCBwYWQgMiBieXRlc1xuXHRcdFx0b3V0cHV0ID0gXCJcIixcblx0XHRcdHRlbXAsIGxlbmd0aFxuXG5cdFx0ZnVuY3Rpb24gZW5jb2RlIChudW0pIHtcblx0XHRcdHJldHVybiBsb29rdXAuY2hhckF0KG51bSlcblx0XHR9XG5cblx0XHRmdW5jdGlvbiB0cmlwbGV0VG9CYXNlNjQgKG51bSkge1xuXHRcdFx0cmV0dXJuIGVuY29kZShudW0gPj4gMTggJiAweDNGKSArIGVuY29kZShudW0gPj4gMTIgJiAweDNGKSArIGVuY29kZShudW0gPj4gNiAmIDB4M0YpICsgZW5jb2RlKG51bSAmIDB4M0YpXG5cdFx0fVxuXG5cdFx0Ly8gZ28gdGhyb3VnaCB0aGUgYXJyYXkgZXZlcnkgdGhyZWUgYnl0ZXMsIHdlJ2xsIGRlYWwgd2l0aCB0cmFpbGluZyBzdHVmZiBsYXRlclxuXHRcdGZvciAoaSA9IDAsIGxlbmd0aCA9IHVpbnQ4Lmxlbmd0aCAtIGV4dHJhQnl0ZXM7IGkgPCBsZW5ndGg7IGkgKz0gMykge1xuXHRcdFx0dGVtcCA9ICh1aW50OFtpXSA8PCAxNikgKyAodWludDhbaSArIDFdIDw8IDgpICsgKHVpbnQ4W2kgKyAyXSlcblx0XHRcdG91dHB1dCArPSB0cmlwbGV0VG9CYXNlNjQodGVtcClcblx0XHR9XG5cblx0XHQvLyBwYWQgdGhlIGVuZCB3aXRoIHplcm9zLCBidXQgbWFrZSBzdXJlIHRvIG5vdCBmb3JnZXQgdGhlIGV4dHJhIGJ5dGVzXG5cdFx0c3dpdGNoIChleHRyYUJ5dGVzKSB7XG5cdFx0XHRjYXNlIDE6XG5cdFx0XHRcdHRlbXAgPSB1aW50OFt1aW50OC5sZW5ndGggLSAxXVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKHRlbXAgPj4gMilcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA8PCA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSAnPT0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0XHRjYXNlIDI6XG5cdFx0XHRcdHRlbXAgPSAodWludDhbdWludDgubGVuZ3RoIC0gMl0gPDwgOCkgKyAodWludDhbdWludDgubGVuZ3RoIC0gMV0pXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUodGVtcCA+PiAxMClcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA+PiA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPDwgMikgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gJz0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG91dHB1dFxuXHR9XG5cblx0ZXhwb3J0cy50b0J5dGVBcnJheSA9IGI2NFRvQnl0ZUFycmF5XG5cdGV4cG9ydHMuZnJvbUJ5dGVBcnJheSA9IHVpbnQ4VG9CYXNlNjRcbn0odHlwZW9mIGV4cG9ydHMgPT09ICd1bmRlZmluZWQnID8gKHRoaXMuYmFzZTY0anMgPSB7fSkgOiBleHBvcnRzKSlcbiIsImV4cG9ydHMucmVhZCA9IGZ1bmN0aW9uIChidWZmZXIsIG9mZnNldCwgaXNMRSwgbUxlbiwgbkJ5dGVzKSB7XG4gIHZhciBlLCBtXG4gIHZhciBlTGVuID0gbkJ5dGVzICogOCAtIG1MZW4gLSAxXG4gIHZhciBlTWF4ID0gKDEgPDwgZUxlbikgLSAxXG4gIHZhciBlQmlhcyA9IGVNYXggPj4gMVxuICB2YXIgbkJpdHMgPSAtN1xuICB2YXIgaSA9IGlzTEUgPyAobkJ5dGVzIC0gMSkgOiAwXG4gIHZhciBkID0gaXNMRSA/IC0xIDogMVxuICB2YXIgcyA9IGJ1ZmZlcltvZmZzZXQgKyBpXVxuXG4gIGkgKz0gZFxuXG4gIGUgPSBzICYgKCgxIDw8ICgtbkJpdHMpKSAtIDEpXG4gIHMgPj49ICgtbkJpdHMpXG4gIG5CaXRzICs9IGVMZW5cbiAgZm9yICg7IG5CaXRzID4gMDsgZSA9IGUgKiAyNTYgKyBidWZmZXJbb2Zmc2V0ICsgaV0sIGkgKz0gZCwgbkJpdHMgLT0gOCkge31cblxuICBtID0gZSAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBlID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBtTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IG0gPSBtICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgaWYgKGUgPT09IDApIHtcbiAgICBlID0gMSAtIGVCaWFzXG4gIH0gZWxzZSBpZiAoZSA9PT0gZU1heCkge1xuICAgIHJldHVybiBtID8gTmFOIDogKChzID8gLTEgOiAxKSAqIEluZmluaXR5KVxuICB9IGVsc2Uge1xuICAgIG0gPSBtICsgTWF0aC5wb3coMiwgbUxlbilcbiAgICBlID0gZSAtIGVCaWFzXG4gIH1cbiAgcmV0dXJuIChzID8gLTEgOiAxKSAqIG0gKiBNYXRoLnBvdygyLCBlIC0gbUxlbilcbn1cblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uIChidWZmZXIsIHZhbHVlLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbSwgY1xuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIHJ0ID0gKG1MZW4gPT09IDIzID8gTWF0aC5wb3coMiwgLTI0KSAtIE1hdGgucG93KDIsIC03NykgOiAwKVxuICB2YXIgaSA9IGlzTEUgPyAwIDogKG5CeXRlcyAtIDEpXG4gIHZhciBkID0gaXNMRSA/IDEgOiAtMVxuICB2YXIgcyA9IHZhbHVlIDwgMCB8fCAodmFsdWUgPT09IDAgJiYgMSAvIHZhbHVlIDwgMCkgPyAxIDogMFxuXG4gIHZhbHVlID0gTWF0aC5hYnModmFsdWUpXG5cbiAgaWYgKGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICBtID0gaXNOYU4odmFsdWUpID8gMSA6IDBcbiAgICBlID0gZU1heFxuICB9IGVsc2Uge1xuICAgIGUgPSBNYXRoLmZsb29yKE1hdGgubG9nKHZhbHVlKSAvIE1hdGguTE4yKVxuICAgIGlmICh2YWx1ZSAqIChjID0gTWF0aC5wb3coMiwgLWUpKSA8IDEpIHtcbiAgICAgIGUtLVxuICAgICAgYyAqPSAyXG4gICAgfVxuICAgIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgdmFsdWUgKz0gcnQgLyBjXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbHVlICs9IHJ0ICogTWF0aC5wb3coMiwgMSAtIGVCaWFzKVxuICAgIH1cbiAgICBpZiAodmFsdWUgKiBjID49IDIpIHtcbiAgICAgIGUrK1xuICAgICAgYyAvPSAyXG4gICAgfVxuXG4gICAgaWYgKGUgKyBlQmlhcyA+PSBlTWF4KSB7XG4gICAgICBtID0gMFxuICAgICAgZSA9IGVNYXhcbiAgICB9IGVsc2UgaWYgKGUgKyBlQmlhcyA+PSAxKSB7XG4gICAgICBtID0gKHZhbHVlICogYyAtIDEpICogTWF0aC5wb3coMiwgbUxlbilcbiAgICAgIGUgPSBlICsgZUJpYXNcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IHZhbHVlICogTWF0aC5wb3coMiwgZUJpYXMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gMFxuICAgIH1cbiAgfVxuXG4gIGZvciAoOyBtTGVuID49IDg7IGJ1ZmZlcltvZmZzZXQgKyBpXSA9IG0gJiAweGZmLCBpICs9IGQsIG0gLz0gMjU2LCBtTGVuIC09IDgpIHt9XG5cbiAgZSA9IChlIDw8IG1MZW4pIHwgbVxuICBlTGVuICs9IG1MZW5cbiAgZm9yICg7IGVMZW4gPiAwOyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBlICYgMHhmZiwgaSArPSBkLCBlIC89IDI1NiwgZUxlbiAtPSA4KSB7fVxuXG4gIGJ1ZmZlcltvZmZzZXQgKyBpIC0gZF0gfD0gcyAqIDEyOFxufVxuIiwiXG4vKipcbiAqIGlzQXJyYXlcbiAqL1xuXG52YXIgaXNBcnJheSA9IEFycmF5LmlzQXJyYXk7XG5cbi8qKlxuICogdG9TdHJpbmdcbiAqL1xuXG52YXIgc3RyID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztcblxuLyoqXG4gKiBXaGV0aGVyIG9yIG5vdCB0aGUgZ2l2ZW4gYHZhbGBcbiAqIGlzIGFuIGFycmF5LlxuICpcbiAqIGV4YW1wbGU6XG4gKlxuICogICAgICAgIGlzQXJyYXkoW10pO1xuICogICAgICAgIC8vID4gdHJ1ZVxuICogICAgICAgIGlzQXJyYXkoYXJndW1lbnRzKTtcbiAqICAgICAgICAvLyA+IGZhbHNlXG4gKiAgICAgICAgaXNBcnJheSgnJyk7XG4gKiAgICAgICAgLy8gPiBmYWxzZVxuICpcbiAqIEBwYXJhbSB7bWl4ZWR9IHZhbFxuICogQHJldHVybiB7Ym9vbH1cbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGlzQXJyYXkgfHwgZnVuY3Rpb24gKHZhbCkge1xuICByZXR1cm4gISEgdmFsICYmICdbb2JqZWN0IEFycmF5XScgPT0gc3RyLmNhbGwodmFsKTtcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJ2ZXJzaW9uXCI6IFwiXCJcbn1cbiIsIi8qKlxuICogRXBpY2VudGVyIEphdmFzY3JpcHQgbGlicmFyaWVzXG4gKiB2PCU9IHZlcnNpb24gJT5cbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9mb3Jpby9lcGljZW50ZXItanMtbGlic1xuICovXG5cbnZhciBGID0ge1xuICAgIHV0aWw6IHt9LFxuICAgIGZhY3Rvcnk6IHt9LFxuICAgIHRyYW5zcG9ydDoge30sXG4gICAgc3RvcmU6IHt9LFxuICAgIHNlcnZpY2U6IHt9LFxuICAgIG1hbmFnZXI6IHtcbiAgICAgICAgc3RyYXRlZ3k6IHt9XG4gICAgfSxcblxufTtcblxuRi51dGlsLnF1ZXJ5ID0gcmVxdWlyZSgnLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbkYudXRpbC5tYWtlU2VxdWVuY2UgPSByZXF1aXJlKCcuL3V0aWwvbWFrZS1zZXF1ZW5jZScpO1xuRi51dGlsLnJ1biA9IHJlcXVpcmUoJy4vdXRpbC9ydW4tdXRpbCcpO1xuRi51dGlsLmNsYXNzRnJvbSA9IHJlcXVpcmUoJy4vdXRpbC9pbmhlcml0Jyk7XG5cbkYuZmFjdG9yeS5UcmFuc3BvcnQgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5GLnRyYW5zcG9ydC5BamF4ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvYWpheC1odHRwLXRyYW5zcG9ydCcpO1xuXG5GLnNlcnZpY2UuVVJMID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xuRi5zZXJ2aWNlLkNvbmZpZyA9IHJlcXVpcmUoJy4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbkYuc2VydmljZS5SdW4gPSByZXF1aXJlKCcuL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRmlsZSA9IHJlcXVpcmUoJy4vc2VydmljZS9hZG1pbi1maWxlLXNlcnZpY2UnKTtcbkYuc2VydmljZS5WYXJpYWJsZXMgPSByZXF1aXJlKCcuL3NlcnZpY2UvdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRGF0YSA9IHJlcXVpcmUoJy4vc2VydmljZS9kYXRhLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuQXV0aCA9IHJlcXVpcmUoJy4vc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuV29ybGQgPSByZXF1aXJlKCcuL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5TdGF0ZSA9IHJlcXVpcmUoJy4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLlVzZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLk1lbWJlciA9IHJlcXVpcmUoJy4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Bc3NldCA9IHJlcXVpcmUoJy4vc2VydmljZS9hc3NldC1hcGktYWRhcHRlcicpO1xuXG5GLnN0b3JlLkNvb2tpZSA9IHJlcXVpcmUoJy4vc3RvcmUvY29va2llLXN0b3JlJyk7XG5GLmZhY3RvcnkuU3RvcmUgPSByZXF1aXJlKCcuL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcblxuRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvc2NlbmFyaW8tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLlJ1bk1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2F1dGgtbWFuYWdlcicpO1xuRi5tYW5hZ2VyLldvcmxkTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvd29ybGQtbWFuYWdlcicpO1xuXG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ2Fsd2F5cy1uZXcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvYWx3YXlzLW5ldy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5Wydjb25kaXRpb25hbC1jcmVhdGlvbiddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5LmlkZW50aXR5ID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9pZGVudGl0eS1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtcGVyc2lzdGVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLWluaXRpYWxpemVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpO1xuXG5GLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXInKTtcbkYuc2VydmljZS5DaGFubmVsID0gcmVxdWlyZSgnLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xuXG5GLnZlcnNpb24gPSAnPCU9IHZlcnNpb24gJT4nO1xuRi5hcGkgPSByZXF1aXJlKCcuL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuZ2xvYmFsLkYgPSBGO1xubW9kdWxlLmV4cG9ydHMgPSBGO1xuIiwiLyoqXG4qICMjIEF1dGhvcml6YXRpb24gTWFuYWdlclxuKlxuKiBUaGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIG1hbmFnZSB1c2VyIGF1dGhlbnRpY2F0aW9uIChsb2dnaW5nIGluIGFuZCBvdXQpIGFuZCBhdXRob3JpemF0aW9uIChrZWVwaW5nIHRyYWNrIG9mIHRva2Vucywgc2Vzc2lvbnMsIGFuZCBncm91cHMpIGZvciBwcm9qZWN0cy5cbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBpcyBtb3N0IHVzZWZ1bCBmb3IgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSB3aXRoIGFuIGFjY2VzcyBsZXZlbCBvZiBbQXV0aGVudGljYXRlZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2FjY2VzcykuIFRoZXNlIHByb2plY3RzIGFyZSBhY2Nlc3NlZCBieSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiBvbmUgb3IgbW9yZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS5cbipcbiogIyMjI1VzaW5nIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXJcbipcbiogVG8gdXNlIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZDpcbipcbiogICAgICAgdmFyIGF1dGhNZ3IgPSBuZXcgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKHtcbiogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgIHVzZXJOYW1lOiAnZW5kdXNlcjEnLFxuKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiogICAgICAgfSk7XG4qICAgICAgIGF1dGhNZ3IubG9naW4oKS50aGVuKGZ1bmN0aW9uICgpIHtcbiogICAgICAgICAgIGF1dGhNZ3IuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuKiAgICAgICB9KTtcbipcbipcbiogVGhlIGBvcHRpb25zYCBvYmplY3QgcGFzc2VkIHRvIHRoZSBgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKClgIGNhbGwgY2FuIGluY2x1ZGU6XG4qXG4qICAgKiBgYWNjb3VudGA6IFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICogYHVzZXJOYW1lYDogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLlxuKiAgICogYHBhc3N3b3JkYDogUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLlxuKiAgICogYHByb2plY3RgOiBUaGUgKipQcm9qZWN0IElEKiogZm9yIHRoZSBwcm9qZWN0IHRvIGxvZyB0aGlzIHVzZXIgaW50by4gT3B0aW9uYWwuXG4qICAgKiBgZ3JvdXBJZGA6IElkIG9mIHRoZSBncm91cCB0byB3aGljaCBgdXNlck5hbWVgIGJlbG9uZ3MuIFJlcXVpcmVkIGZvciBlbmQgdXNlcnMgaWYgdGhlIGBwcm9qZWN0YCBpcyBzcGVjaWZpZWQuXG4qXG4qIElmIHlvdSBwcmVmZXIgc3RhcnRpbmcgZnJvbSBhIHRlbXBsYXRlLCB0aGUgRXBpY2VudGVyIEpTIExpYnMgW0xvZ2luIENvbXBvbmVudF0oLi4vLi4vI2NvbXBvbmVudHMpIHVzZXMgdGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBhcyB3ZWxsLiBUaGlzIHNhbXBsZSBIVE1MIHBhZ2UgKGFuZCBhc3NvY2lhdGVkIENTUyBhbmQgSlMgZmlsZXMpIHByb3ZpZGVzIGEgbG9naW4gZm9ybSBmb3IgdGVhbSBtZW1iZXJzIGFuZCBlbmQgdXNlcnMgb2YgeW91ciBwcm9qZWN0LiBJdCBhbHNvIGluY2x1ZGVzIGEgZ3JvdXAgc2VsZWN0b3IgZm9yIGVuZCB1c2VycyB0aGF0IGFyZSBtZW1iZXJzIG9mIG11bHRpcGxlIGdyb3Vwcy5cbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBBdXRoQWRhcHRlciA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xudmFyIE1lbWJlckFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlcicpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIEJ1ZmZlciA9IHJlcXVpcmUoJ2J1ZmZlcicpLkJ1ZmZlcjtcbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4va2V5LW5hbWVzJyk7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBXaGVyZSB0byBzdG9yZSB1c2VyIGFjY2VzcyB0b2tlbnMgZm9yIHRlbXBvcmFyeSBhY2Nlc3MuIERlZmF1bHRzIHRvIHN0b3JpbmcgaW4gYSBjb29raWUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBzdG9yZTogeyBzeW5jaHJvbm91czogdHJ1ZSB9XG59O1xuXG52YXIgRVBJX0NPT0tJRV9LRVkgPSBrZXlOYW1lcy5FUElfQ09PS0lFX0tFWTtcbnZhciBFUElfU0VTU0lPTl9LRVkgPSBrZXlOYW1lcy5FUElfU0VTU0lPTl9LRVk7XG52YXIgc3RvcmU7XG52YXIgdG9rZW47XG52YXIgc2Vzc2lvbjtcblxuZnVuY3Rpb24gc2F2ZVNlc3Npb24odXNlckluZm8sIHN0b3JlKSB7XG4gICAgdmFyIHNlcmlhbGl6ZWQgPSBKU09OLnN0cmluZ2lmeSh1c2VySW5mbyk7XG4gICAgc3RvcmUuc2V0KEVQSV9TRVNTSU9OX0tFWSwgc2VyaWFsaXplZCk7XG5cbiAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgLy9qc2NzOmRpc2FibGVcbiAgICBzdG9yZS5zZXQoRVBJX0NPT0tJRV9LRVksIHVzZXJJbmZvLmF1dGhfdG9rZW4pO1xufVxuXG5mdW5jdGlvbiBnZXRTZXNzaW9uKHN0b3JlKSB7XG4gICAgdmFyIHNlc3Npb24gPSBzdG9yZS5nZXQoRVBJX1NFU1NJT05fS0VZKSB8fCAne30nO1xuICAgIHJldHVybiBKU09OLnBhcnNlKHNlc3Npb24pO1xufVxuXG5mdW5jdGlvbiBBdXRoTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZSh0aGlzLm9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB0aGlzLm9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICAvLyBudWxsIG1pZ2h0IHNwZWNpZmllZCB0byBkaXNhYmxlIHByb2plY3QgZmlsdGVyaW5nXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wcm9qZWN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5zdG9yZS5yb290ID09PSB1bmRlZmluZWQgJiYgdGhpcy5vcHRpb25zLmFjY291bnQgJiYgdGhpcy5vcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLnN0b3JlLnJvb3QgPSAnL2FwcC8nICsgdGhpcy5vcHRpb25zLmFjY291bnQgKyAnLycgKyB0aGlzLm9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB0aGlzLnN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHRoaXMub3B0aW9ucy5zdG9yZSk7XG4gICAgc2Vzc2lvbiA9IGdldFNlc3Npb24odGhpcy5zdG9yZSk7XG4gICAgdG9rZW4gPSB0aGlzLnN0b3JlLmdldChFUElfQ09PS0lFX0tFWSkgfHwgJyc7XG4gICAgLy9qc2hpbnQgY2FtZWxjYXNlOiBmYWxzZVxuICAgIC8vanNjczpkaXNhYmxlXG4gICAgdGhpcy5hdXRoQWRhcHRlciA9IG5ldyBBdXRoQWRhcHRlcih0aGlzLm9wdGlvbnMsIHsgdG9rZW46IHNlc3Npb24uYXV0aF90b2tlbiB9KTtcbn1cblxudmFyIF9maW5kVXNlckluR3JvdXAgPSBmdW5jdGlvbiAobWVtYmVycywgaWQpIHtcbiAgICBmb3IgKHZhciBqID0gMDsgajxtZW1iZXJzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIGlmIChtZW1iZXJzW2pdLnVzZXJJZCA9PT0gaWQpIHtcbiAgICAgICAgICAgIHJldHVybiBtZW1iZXJzW2pdO1xuICAgICAgICB9XG4gICAgfVxuXG5cbiAgICByZXR1cm4gbnVsbDtcbn07XG5cbkF1dGhNYW5hZ2VyLnByb3RvdHlwZSA9ICQuZXh0ZW5kKEF1dGhNYW5hZ2VyLnByb3RvdHlwZSwge1xuXG4gICAgLyoqXG4gICAgKiBMb2dzIHVzZXIgaW4uXG4gICAgKlxuICAgICogKipFeGFtcGxlKipcbiAgICAqXG4gICAgKiAgICAgICBhdXRoTWdyLmxvZ2luKHtcbiAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAqICAgICAgICAgICB1c2VyTmFtZTogJ2VuZHVzZXIxJyxcbiAgICAqICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJ1xuICAgICogICAgICAgfSlcbiAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbihzdGF0dXNPYmopIHtcbiAgICAqICAgICAgICAgICAgICAgLy8gaWYgZW5kdXNlcjEgYmVsb25ncyB0byBleGFjdGx5IG9uZSBncm91cFxuICAgICogICAgICAgICAgICAgICAvLyAob3IgaWYgdGhlIGxvZ2luKCkgY2FsbCBpcyBtb2RpZmllZCB0byBpbmNsdWRlIHRoZSBncm91cCBpZClcbiAgICAqICAgICAgICAgICAgICAgLy8gY29udGludWUgaGVyZVxuICAgICogICAgICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLmZhaWwoZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gbXVsdGlwbGUgZ3JvdXBzLFxuICAgICogICAgICAgICAgICAgICAvLyB0aGUgbG9naW4oKSBjYWxsIGZhaWxzXG4gICAgKiAgICAgICAgICAgICAgIC8vIGFuZCByZXR1cm5zIGFsbCBncm91cHMgb2Ygd2hpY2ggdGhlIHVzZXIgaXMgYSBtZW1iZXJcbiAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpIDwgc3RhdHVzT2JqLnVzZXJHcm91cHMubGVuZ3RoOyBpKyspIHtcbiAgICAqICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHN0YXR1c09iai51c2VyR3JvdXBzW2ldLm5hbWUsIHN0YXR1c09iai51c2VyR3JvdXBzW2ldLmdyb3VwSWQpO1xuICAgICogICAgICAgICAgICAgICB9XG4gICAgKiAgICAgICAgICAgfSk7XG4gICAgKlxuICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAqXG4gICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuIElmIG5vdCBwYXNzZWQgaW4gd2hlbiBjcmVhdGluZyBhbiBpbnN0YW5jZSBvZiB0aGUgbWFuYWdlciAoYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCksIHRoZXNlIG9wdGlvbnMgc2hvdWxkIGluY2x1ZGU6XG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMuYWNjb3VudGAgVGhlIGFjY291bnQgaWQgZm9yIHRoaXMgYHVzZXJOYW1lYC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciB0aGUgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMudXNlck5hbWVgIEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5wYXNzd29yZGAgUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnByb2plY3RgIChPcHRpb25hbCkgVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGUgcHJvamVjdCB0byBsb2cgdGhpcyB1c2VyIGludG8uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMuZ3JvdXBJZGAgVGhlIGlkIG9mIHRoZSBncm91cCB0byB3aGljaCBgdXNlck5hbWVgIGJlbG9uZ3MuIFJlcXVpcmVkIGZvciBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIGlmIHRoZSBgcHJvamVjdGAgaXMgc3BlY2lmaWVkIGFuZCBpZiB0aGUgZW5kIHVzZXJzIGFyZSBtZW1iZXJzIG9mIG11bHRpcGxlIFtncm91cHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvdGhlcndpc2Ugb3B0aW9uYWwuXG4gICAgKi9cbiAgICBsb2dpbjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgYWRhcHRlck9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHN1Y2Nlc3M6ICQubm9vcCwgZXJyb3I6ICQubm9vcCB9LCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICB2YXIgb3V0U3VjY2VzcyA9IGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgIHZhciBvdXRFcnJvciA9IGFkYXB0ZXJPcHRpb25zLmVycm9yO1xuICAgICAgICB2YXIgZ3JvdXBJZCA9IGFkYXB0ZXJPcHRpb25zLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGRlY29kZVRva2VuID0gZnVuY3Rpb24gKHRva2VuKSB7XG4gICAgICAgICAgICB2YXIgZW5jb2RlZCA9IHRva2VuLnNwbGl0KCcuJylbMV07XG4gICAgICAgICAgICB3aGlsZSAoZW5jb2RlZC5sZW5ndGggJSA0ICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgZW5jb2RlZCArPSAnPSc7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBkZWNvZGUgPSB3aW5kb3cuYXRvYiA/IHdpbmRvdy5hdG9iIDogZnVuY3Rpb24gKGVuY29kZWQpIHsgcmV0dXJuIG5ldyBCdWZmZXIoZW5jb2RlZCwgJ2Jhc2U2NCcpLnRvU3RyaW5nKCdhc2NpaScpOyB9O1xuXG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShkZWNvZGUoZW5jb2RlZCkpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBoYW5kbGVHcm91cEVycm9yID0gZnVuY3Rpb24gKG1lc3NhZ2UsIHN0YXR1c0NvZGUsIGRhdGEpIHtcbiAgICAgICAgICAgIC8vIGxvZ291dCB0aGUgdXNlciBzaW5jZSBpdCdzIGluIGFuIGludmFsaWQgc3RhdGUgd2l0aCBubyBncm91cCBzZWxlY3RlZFxuICAgICAgICAgICAgX3RoaXMubG9nb3V0KCkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdmFyIGVycm9yID0gJC5leHRlbmQodHJ1ZSwge30sIGRhdGEsIHsgc3RhdHVzVGV4dDogbWVzc2FnZSwgc3RhdHVzOiBzdGF0dXNDb2RlIH0pO1xuICAgICAgICAgICAgICAgICRkLnJlamVjdChlcnJvcik7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgaGFuZGxlU3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgLy9qc2hpbnQgY2FtZWxjYXNlOiBmYWxzZVxuICAgICAgICAgICAgLy9qc2NzOmRpc2FibGVcbiAgICAgICAgICAgIHRva2VuID0gcmVzcG9uc2UuYWNjZXNzX3Rva2VuO1xuICAgICAgICAgICAgdmFyIHVzZXJJbmZvID0gZGVjb2RlVG9rZW4odG9rZW4pO1xuICAgICAgICAgICAgdmFyIHVzZXJHcm91cE9wdHMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgYWRhcHRlck9wdGlvbnMsIHsgc3VjY2VzczogJC5ub29wLCB0b2tlbjogdG9rZW4gfSk7XG4gICAgICAgICAgICBfdGhpcy5nZXRVc2VyR3JvdXBzKHsgdXNlcklkOiB1c2VySW5mby51c2VyX2lkLCB0b2tlbjogdG9rZW4gfSwgdXNlckdyb3VwT3B0cykuZG9uZSggZnVuY3Rpb24gKG1lbWJlckluZm8pIHtcbiAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IHthdXRoOiByZXNwb25zZSwgdXNlcjogdXNlckluZm8sIHVzZXJHcm91cHM6IG1lbWJlckluZm8sIGdyb3VwU2VsZWN0aW9uOiB7fSB9O1xuXG4gICAgICAgICAgICAgICAgdmFyIHNlc3Npb25JbmZvID0ge1xuICAgICAgICAgICAgICAgICAgICAnYXV0aF90b2tlbic6IHRva2VuLFxuICAgICAgICAgICAgICAgICAgICAnYWNjb3VudCc6IGFkYXB0ZXJPcHRpb25zLmFjY291bnQsXG4gICAgICAgICAgICAgICAgICAgICdwcm9qZWN0JzogYWRhcHRlck9wdGlvbnMucHJvamVjdCxcbiAgICAgICAgICAgICAgICAgICAgJ3VzZXJJZCc6IHVzZXJJbmZvLnVzZXJfaWRcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIC8vIFRoZSBncm91cCBpcyBub3QgcmVxdWlyZWQgaWYgdGhlIHVzZXIgaXMgbm90IGxvZ2dpbmcgaW50byBhIHByb2plY3RcbiAgICAgICAgICAgICAgICBpZiAoIWFkYXB0ZXJPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgc2F2ZVNlc3Npb24oc2Vzc2lvbkluZm8sIF90aGlzLnN0b3JlKTtcbiAgICAgICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIGdyb3VwID0gbnVsbDtcbiAgICAgICAgICAgICAgICBpZiAobWVtYmVySW5mby5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgaGFuZGxlR3JvdXBFcnJvcignVGhlIHVzZXIgaGFzIG5vIGdyb3VwcyBhc3NvY2lhdGVkIGluIHRoaXMgYWNjb3VudCcsIDQwMSwgZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1lbWJlckluZm8ubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFNlbGVjdCB0aGUgb25seSBncm91cFxuICAgICAgICAgICAgICAgICAgICBncm91cCA9IG1lbWJlckluZm9bMF07XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZW1iZXJJbmZvLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGdyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBmaWx0ZXJlZEdyb3VwcyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAocmVzR3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzR3JvdXAuZ3JvdXBJZCA9PT0gZ3JvdXBJZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBmaWx0ZXJlZEdyb3Vwcy5sZW5ndGggPT09IDEgPyBmaWx0ZXJlZEdyb3Vwc1swXSA6IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGdyb3VwU2VsZWN0aW9uID0gZ3JvdXAuZ3JvdXBJZDtcbiAgICAgICAgICAgICAgICAgICAgZGF0YS5ncm91cFNlbGVjdGlvblthZGFwdGVyT3B0aW9ucy5wcm9qZWN0XSA9IGdyb3VwU2VsZWN0aW9uO1xuICAgICAgICAgICAgICAgICAgICB2YXIgc2Vzc2lvbkluZm9XaXRoR3JvdXAgPSAkLmV4dGVuZCh7fSwgc2Vzc2lvbkluZm8sIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICdncm91cElkJzogZ3JvdXAuZ3JvdXBJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICdncm91cE5hbWUnOiBncm91cC5uYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ2lzRmFjJzogX2ZpbmRVc2VySW5Hcm91cChncm91cC5tZW1iZXJzLCB1c2VySW5mby51c2VyX2lkKS5yb2xlID09PSAnZmFjaWxpdGF0b3InXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBzYXZlU2Vzc2lvbihzZXNzaW9uSW5mb1dpdGhHcm91cCwgX3RoaXMuc3RvcmUpO1xuICAgICAgICAgICAgICAgICAgICBvdXRTdWNjZXNzLmFwcGx5KHRoaXMsIFtkYXRhXSk7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUoZGF0YSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgaGFuZGxlR3JvdXBFcnJvcignVGhpcyB1c2VyIGlzIGFzc29jaWF0ZWQgd2l0aCBtb3JlIHRoYW4gb25lIGdyb3VwLiBQbGVhc2Ugc3BlY2lmeSBhIGdyb3VwIGlkIHRvIGxvZyBpbnRvIGFuZCB0cnkgYWdhaW4nLCA0MDMsIGRhdGEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pLmZhaWwoJGQucmVqZWN0KTtcbiAgICAgICAgfTtcblxuICAgICAgICBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzID0gaGFuZGxlU3VjY2VzcztcbiAgICAgICAgYWRhcHRlck9wdGlvbnMuZXJyb3IgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIGlmIChhZGFwdGVyT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgICAgICAgICAgLy8gVHJ5IHRvIGxvZ2luIGFzIGEgc3lzdGVtIHVzZXJcbiAgICAgICAgICAgICAgICBhZGFwdGVyT3B0aW9ucy5hY2NvdW50ID0gbnVsbDtcbiAgICAgICAgICAgICAgICBhZGFwdGVyT3B0aW9ucy5lcnJvciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgb3V0RXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVqZWN0KHJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgX3RoaXMuYXV0aEFkYXB0ZXIubG9naW4oYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgb3V0RXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICRkLnJlamVjdChyZXNwb25zZSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy5hdXRoQWRhcHRlci5sb2dpbihhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICogTG9ncyB1c2VyIG91dC5cbiAgICAqXG4gICAgKiAqKkV4YW1wbGUqKlxuICAgICpcbiAgICAqICAgICAgIGF1dGhNZ3IubG9nb3V0KCk7XG4gICAgKlxuICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAqXG4gICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgKi9cbiAgICBsb2dvdXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHsgdG9rZW46IHRva2VuIH0sIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIHJlbW92ZUNvb2tpZUZuID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBzdG9yZS5yZW1vdmUoRVBJX0NPT0tJRV9LRVksIGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgICAgIHN0b3JlLnJlbW92ZShFUElfU0VTU0lPTl9LRVksIGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgICAgIHRva2VuID0gJyc7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuYXV0aEFkYXB0ZXIubG9nb3V0KGFkYXB0ZXJPcHRpb25zKS5kb25lKHJlbW92ZUNvb2tpZUZuKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgZXhpc3RpbmcgdXNlciBhY2Nlc3MgdG9rZW4gaWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4uIE90aGVyd2lzZSwgbG9ncyB0aGUgdXNlciBpbiwgY3JlYXRpbmcgYSBuZXcgdXNlciBhY2Nlc3MgdG9rZW4sIGFuZCByZXR1cm5zIHRoZSBuZXcgdG9rZW4uIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VG9rZW4oKVxuICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZygnTXkgdG9rZW4gaXMgJywgdG9rZW4pO1xuICAgICAqICAgICAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICovXG4gICAgZ2V0VG9rZW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICBpZiAodG9rZW4pIHtcbiAgICAgICAgICAgICRkLnJlc29sdmUodG9rZW4pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5sb2dpbihodHRwT3B0aW9ucykudGhlbigkZC5yZXNvbHZlKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGFuIGFycmF5IG9mIGdyb3VwIHJlY29yZHMsIG9uZSBmb3IgZWFjaCBncm91cCBvZiB3aGljaCB0aGUgY3VycmVudCB1c2VyIGlzIGEgbWVtYmVyLiBFYWNoIGdyb3VwIHJlY29yZCBpbmNsdWRlcyB0aGUgZ3JvdXAgYG5hbWVgLCBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGBncm91cElkYC5cbiAgICAgKlxuICAgICAqIElmIHNvbWUgZW5kIHVzZXJzIGluIHlvdXIgcHJvamVjdCBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBncm91cHMsIHRoaXMgaXMgYSB1c2VmdWwgbWV0aG9kIHRvIGNhbGwgb24geW91ciBwcm9qZWN0J3MgbG9naW4gcGFnZS4gV2hlbiB0aGUgdXNlciBhdHRlbXB0cyB0byBsb2cgaW4sIHlvdSBjYW4gdXNlIHRoaXMgdG8gZGlzcGxheSB0aGUgZ3JvdXBzIG9mIHdoaWNoIHRoZSB1c2VyIGlzIG1lbWJlciwgYW5kIGhhdmUgdGhlIHVzZXIgc2VsZWN0IHRoZSBjb3JyZWN0IGdyb3VwIHRvIGxvZyBpbiB0byBmb3IgdGhpcyBzZXNzaW9uLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgLy8gZ2V0IGdyb3VwcyBmb3IgY3VycmVudCB1c2VyXG4gICAgICogICAgICB2YXIgc2Vzc2lvbk9iaiA9IGF1dGhNZ3IuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHsgdXNlcklkOiBzZXNzaW9uT2JqLnVzZXJJZCwgdG9rZW46IHNlc3Npb25PYmouYXV0aF90b2tlbiB9KVxuICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChncm91cHMpIHtcbiAgICAgKiAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpIDwgZ3JvdXBzLmxlbmd0aDsgaSsrKVxuICAgICAqICAgICAgICAgICAgICAgICAgeyBjb25zb2xlLmxvZyhncm91cHNbaV0ubmFtZSk7IH1cbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gZ2V0IGdyb3VwcyBmb3IgcGFydGljdWxhciB1c2VyXG4gICAgICogICAgICBhdXRoTWdyLmdldFVzZXJHcm91cHMoe3VzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHRva2VuOiBzYXZlZFByb2pBY2Nlc3NUb2tlbiB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBwYXJhbXNgIE9iamVjdCB3aXRoIGEgdXNlcklkIGFuZCB0b2tlbiBwcm9wZXJ0aWVzLlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIHVzZXJJZC4gSWYgbG9va2luZyB1cCBncm91cHMgZm9yIHRoZSBjdXJyZW50bHkgbG9nZ2VkIGluIHVzZXIsIHRoaXMgaXMgaW4gdGhlIHNlc3Npb24gaW5mb3JtYXRpb24uIE90aGVyd2lzZSwgcGFzcyBhIHN0cmluZy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy50b2tlbmAgVGhlIGF1dGhvcml6YXRpb24gY3JlZGVudGlhbHMgKGFjY2VzcyB0b2tlbikgdG8gdXNlIGZvciBjaGVja2luZyB0aGUgZ3JvdXBzIGZvciB0aGlzIHVzZXIuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBBIHRlYW0gbWVtYmVyJ3MgdG9rZW4gb3IgYSBwcm9qZWN0IGFjY2VzcyB0b2tlbiBjYW4gYWNjZXNzIGFsbCB0aGUgZ3JvdXBzIGZvciBhbGwgZW5kIHVzZXJzIGluIHRoZSB0ZWFtIG9yIHByb2plY3QuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFVzZXJHcm91cHM6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AgfSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgb3V0U3VjY2VzcyA9IGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3M7XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAvLyBUaGUgbWVtYmVyIEFQSSBpcyBhdCB0aGUgYWNjb3VudCBzY29wZSwgd2UgZmlsdGVyIGJ5IHByb2plY3RcbiAgICAgICAgICAgIGlmIChhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgbWVtYmVySW5mbyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdyb3VwLnByb2plY3QgPT09IGFkYXB0ZXJPcHRpb25zLnByb2plY3Q7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW21lbWJlckluZm9dKTtcbiAgICAgICAgICAgICRkLnJlc29sdmUobWVtYmVySW5mbyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIG1lbWJlckFkYXB0ZXIgPSBuZXcgTWVtYmVyQWRhcHRlcih7IHRva2VuOiBwYXJhbXMudG9rZW4gfSk7XG4gICAgICAgIG1lbWJlckFkYXB0ZXIuZ2V0R3JvdXBzRm9yVXNlcihwYXJhbXMsIGFkYXB0ZXJPcHRpb25zKS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgc2Vzc2lvbiBpbmZvcm1hdGlvbiBmb3IgdGhlIGN1cnJlbnQgdXNlciwgaW5jbHVkaW5nIHRoZSBgdXNlcklkYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGBncm91cElkYCwgYGdyb3VwTmFtZWAsIGBpc0ZhY2AgKHdoZXRoZXIgdGhlIGVuZCB1c2VyIGlzIGEgZmFjaWxpdGF0b3Igb2YgdGhpcyBncm91cCksIGFuZCBgYXV0aF90b2tlbmAgKHVzZXIgYWNjZXNzIHRva2VuKS5cbiAgICAgKlxuICAgICAqICpJbXBvcnRhbnQqOiBUaGlzIG1ldGhvZCBpcyBzeW5jaHJvbm91cy4gVGhlIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgcmV0dXJuZWQgaW1tZWRpYXRlbHkgaW4gYW4gb2JqZWN0OyBubyBjYWxsYmFja3Mgb3IgcHJvbWlzZXMgYXJlIG5lZWRlZC5cbiAgICAgKlxuICAgICAqIEJ5IGRlZmF1bHQsIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgc3RvcmVkIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLiBZb3UgY2FuIGNoYW5nZSB0aGlzIHdpdGggdGhlIGBzdG9yZWAgY29uZmlndXJhdGlvbiBvcHRpb24uXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgc2Vzc2lvbk9iaiA9IGF1dGhNZ3IuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICovXG4gICAgZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbzogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIGdldFNlc3Npb24odGhpcy5zdG9yZSwgb3B0aW9ucyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQXV0aE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDaGFubmVsID0gcmVxdWlyZSgnLi4vc2VydmljZS9jaGFubmVsLXNlcnZpY2UnKTtcblxuLyoqXG4gKiAjIyBDaGFubmVsIE1hbmFnZXJcbiAqXG4gKiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiBUaGUgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIGRlZmF1bHQgW2NvbWV0ZCBKYXZhU2NyaXB0IGxpYnJhcnldKGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvMi9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sKSwgYCQuY29tZXRkYC4gSXQgcHJvdmlkZXMgYSBmZXcgbmljZSBmZWF0dXJlcyB0aGF0IGAkLmNvbWV0ZGAgZG9lc24ndCwgaW5jbHVkaW5nOlxuICpcbiAqICogQXV0b21hdGljIHJlLXN1YnNjcmlwdGlvbiB0byBjaGFubmVscyBpZiB5b3UgbG9zZSB5b3VyIGNvbm5lY3Rpb25cbiAqICogT25saW5lIC8gT2ZmbGluZSBub3RpZmljYXRpb25zXG4gKiAqICdFdmVudHMnIGZvciBjb21ldGQgbm90aWZpY2F0aW9ucyAoaW5zdGVhZCBvZiBoYXZpbmcgdG8gbGlzdGVuIG9uIHNwZWNpZmljIG1ldGEgY2hhbm5lbHMpXG4gKlxuICogV2hpbGUgeW91IGNhbiB3b3JrIGRpcmVjdGx5IHdpdGggdGhlIENoYW5uZWwgTWFuYWdlciB0aHJvdWdoIE5vZGUuanMgKGZvciBleGFtcGxlLCBgcmVxdWlyZSgnbWFuYWdlci9jaGFubmVsLW1hbmFnZXInKWApIC0tIG9yIGV2ZW4gd29yayBkaXJlY3RseSB3aXRoIGAkLmNvbWV0ZGAgYW5kIEVwaWNlbnRlcidzIHVuZGVybHlpbmcgW1B1c2ggQ2hhbm5lbCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLykgLS0gbW9zdCBvZnRlbiBpdCB3aWxsIGJlIGVhc2llc3QgdG8gd29yayB3aXRoIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pLiBUaGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgdGhhdCBpbnN0YW50aWF0ZXMgYSBDaGFubmVsIE1hbmFnZXIgd2l0aCBFcGljZW50ZXItc3BlY2lmaWMgZGVmYXVsdHMuXG4gKlxuICogWW91J2xsIG5lZWQgdG8gaW5jbHVkZSB0aGUgYGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanNgIGxpYnJhcnkgaW4gYWRkaXRpb24gdG8gdGhlIGBlcGljZW50ZXIuanNgIGxpYnJhcnkgaW4geW91ciBwcm9qZWN0IHRvIHVzZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyLiAoU2VlIFtJbmNsdWRpbmcgRXBpY2VudGVyLmpzXSguLi8uLi8jaW5jbHVkZSkuKVxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyIGluIGNsaWVudC1zaWRlIEphdmFTY3JpcHQsIGluc3RhbnRpYXRlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pLCBnZXQgdGhlIGNoYW5uZWwsIHRoZW4gdXNlIHRoZSBjaGFubmVsJ3MgYHN1YnNjcmliZSgpYCBhbmQgYHB1Ymxpc2goKWAgbWV0aG9kcyB0byBzdWJzY3JpYmUgdG8gdG9waWNzIG9yIHB1Ymxpc2ggZGF0YSB0byB0b3BpY3MuXG4gKlxuICogICAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAqICAgICAgICB2YXIgY2hhbm5lbCA9IGNtLmdldENoYW5uZWwoKTtcbiAqXG4gKiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ3RvcGljJywgY2FsbGJhY2spO1xuICogICAgICAgIGNoYW5uZWwucHVibGlzaCgndG9waWMnLCB7IG15RGF0YTogMTAwIH0pO1xuICpcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciBpbnN0YW50aWF0aW5nIGEgQ2hhbm5lbCBNYW5hZ2VyIGluY2x1ZGU6XG4gKlxuICogKiBgb3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyLiBCZXNpZGVzIHRoZSBjb21tb24gb3B0aW9ucyBsaXN0ZWQgaGVyZSwgc2VlIGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCBmb3Igb3RoZXIgc3VwcG9ydGVkIG9wdGlvbnMuXG4gKiAqIGBvcHRpb25zLnVybGAgVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gKiAqIGBvcHRpb25zLndlYnNvY2tldEVuYWJsZWRgIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlIChib29sZWFuKS5cbiAqICogYG9wdGlvbnMuY2hhbm5lbGAgT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgQ2hhbm5lbCBTZXJ2aWNlLiBTZWUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykgZm9yIGRldGFpbHMuXG4gKlxuICovXG52YXIgQ2hhbm5lbE1hbmFnZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIGlmICghJC5jb21ldGQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb21ldGQgbGlicmFyeSBub3QgZm91bmQuIFBsZWFzZSBpbmNsdWRlIGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanMnKTtcbiAgICB9XG4gICAgaWYgKCFvcHRpb25zIHx8ICFvcHRpb25zLnVybCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGFuIHVybCBmb3IgdGhlIGNvbWV0ZCBzZXJ2ZXInKTtcbiAgICB9XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgQ29tZXRkIGVuZHBvaW50IFVSTC5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVybDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBsb2cgbGV2ZWwgZm9yIHRoZSBjaGFubmVsIChsb2dzIHRvIGNvbnNvbGUpLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbG9nTGV2ZWw6ICdpbmZvJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogV2hldGhlciB3ZWJzb2NrZXQgc3VwcG9ydCBpcyBhY3RpdmUuIERlZmF1bHRzIHRvIGBmYWxzZWA7IEVwaWNlbnRlciBkb2Vzbid0IGN1cnJlbnRseSBzdXBwb3J0IGNvbW11bmljYXRpb24gdGhyb3VnaCB3ZWJzb2NrZXRzLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIHdlYnNvY2tldEVuYWJsZWQ6IGZhbHNlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBJZiBmYWxzZSBlYWNoIGluc3RhbmNlIG9mIENoYW5uZWwgd2lsbCBoYXZlIGEgc2VwYXJhdGUgY29tZXRkIGNvbm5lY3Rpb24gdG8gc2VydmVyLCB3aGljaCBjb3VsZCBiZSBub2lzeS4gU2V0IHRvIHRydWUgdG8gcmUtdXNlIHRoZSBzYW1lIGNvbm5lY3Rpb24gYWNyb3NzIGluc3RhbmNlcy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBzaGFyZUNvbm5lY3Rpb246IGZhbHNlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPdGhlciBkZWZhdWx0cyB0byBwYXNzIG9uIHRvIGluc3RhbmNlcyBvZiB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSwgd2hpY2ggYXJlIGNyZWF0ZWQgdGhyb3VnaCBgZ2V0Q2hhbm5lbCgpYC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIGNoYW5uZWw6IHtcblxuICAgICAgICB9XG4gICAgfTtcbiAgICB2YXIgZGVmYXVsdENvbWV0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG5cbiAgICBpZiAoZGVmYXVsdENvbWV0T3B0aW9ucy5zaGFyZUNvbm5lY3Rpb24gJiYgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQpIHtcbiAgICAgICAgdGhpcy5jb21ldGQgPSBDaGFubmVsTWFuYWdlci5wcm90b3R5cGUuX2NvbWV0ZDtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuICAgIHZhciBjb21ldGQgPSBuZXcgJC5Db21ldGQoKTtcbiAgICBDaGFubmVsTWFuYWdlci5wcm90b3R5cGUuX2NvbWV0ZCA9IGNvbWV0ZDtcblxuICAgIGNvbWV0ZC53ZWJzb2NrZXRFbmFibGVkID0gZGVmYXVsdENvbWV0T3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkO1xuXG4gICAgdGhpcy5pc0Nvbm5lY3RlZCA9IGZhbHNlO1xuICAgIHZhciBjb25uZWN0aW9uQnJva2VuID0gZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyKCdkaXNjb25uZWN0JywgbWVzc2FnZSk7XG4gICAgfTtcbiAgICB2YXIgY29ubmVjdGlvblN1Y2NlZWRlZCA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIG1lID0gdGhpcztcblxuICAgIGNvbWV0ZC5jb25maWd1cmUoZGVmYXVsdENvbWV0T3B0aW9ucyk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Nvbm5lY3QnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICB2YXIgd2FzQ29ubmVjdGVkID0gdGhpcy5pc0Nvbm5lY3RlZDtcbiAgICAgICAgdGhpcy5pc0Nvbm5lY3RlZCA9IChtZXNzYWdlLnN1Y2Nlc3NmdWwgPT09IHRydWUpO1xuICAgICAgICBpZiAoIXdhc0Nvbm5lY3RlZCAmJiB0aGlzLmlzQ29ubmVjdGVkKSB7IC8vQ29ubmVjdGluZyBmb3IgdGhlIGZpcnN0IHRpbWVcbiAgICAgICAgICAgIGNvbm5lY3Rpb25TdWNjZWVkZWQuY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfSBlbHNlIGlmICh3YXNDb25uZWN0ZWQgJiYgIXRoaXMuaXNDb25uZWN0ZWQpIHsgLy9Pbmx5IHRocm93IGRpc2Nvbm5lY3RlZCBtZXNzYWdlIGZybyB0aGUgZmlyc3QgZGlzY29ubmVjdCwgbm90IG9uY2UgcGVyIHRyeVxuICAgICAgICAgICAgY29ubmVjdGlvbkJyb2tlbi5jYWxsKHRoaXMsIG1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgfS5iaW5kKHRoaXMpKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvZGlzY29ubmVjdCcsIGNvbm5lY3Rpb25Ccm9rZW4pO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9oYW5kc2hha2UnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICBpZiAobWVzc2FnZS5zdWNjZXNzZnVsKSB7XG4gICAgICAgICAgICAvL2h0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHRfc3Vic2NyaWJlLmh0bWwjamF2YXNjcmlwdF9zdWJzY3JpYmVfbWV0YV9jaGFubmVsc1xuICAgICAgICAgICAgLy8gXiBcImR5bmFtaWMgc3Vic2NyaXB0aW9ucyBhcmUgY2xlYXJlZCAobGlrZSBhbnkgb3RoZXIgc3Vic2NyaXB0aW9uKSBhbmQgdGhlIGFwcGxpY2F0aW9uIG5lZWRzIHRvIGZpZ3VyZSBvdXQgd2hpY2ggZHluYW1pYyBzdWJzY3JpcHRpb24gbXVzdCBiZSBwZXJmb3JtZWQgYWdhaW5cIlxuICAgICAgICAgICAgY29tZXRkLmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAkKG1lLmN1cnJlbnRTdWJzY3JpcHRpb25zKS5lYWNoKGZ1bmN0aW9uIChpbmRleCwgc3Vicykge1xuICAgICAgICAgICAgICAgICAgICBjb21ldGQucmVzdWJzY3JpYmUoc3Vicyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy9PdGhlciBpbnRlcmVzdGluZyBldmVudHMgZm9yIHJlZmVyZW5jZVxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvc3Vic2NyaWJlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcignc3Vic2NyaWJlJywgbWVzc2FnZSk7XG4gICAgfSk7XG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS91bnN1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3Vuc3Vic2NyaWJlJywgbWVzc2FnZSk7XG4gICAgfSk7XG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9wdWJsaXNoJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcigncHVibGlzaCcsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWNjZXNzZnVsJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcignZXJyb3InLCBtZXNzYWdlKTtcbiAgICB9KTtcblxuICAgIGNvbWV0ZC5oYW5kc2hha2UoKTtcblxuICAgIHRoaXMuY29tZXRkID0gY29tZXRkO1xufTtcblxuXG5DaGFubmVsTWFuYWdlci5wcm90b3R5cGUgPSAkLmV4dGVuZChDaGFubmVsTWFuYWdlci5wcm90b3R5cGUsIHtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW5kIHJldHVybnMgYSBjaGFubmVsLCB0aGF0IGlzLCBhbiBpbnN0YW5jZSBvZiBhIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gICAgICpcbiAgICAgKiAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAgICAgKiAgICAgIGNoYW5uZWwucHVibGlzaCgndG9waWMnLCB7IG15RGF0YTogMTAwIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge09iamVjdHxTdHJpbmd9IGBvcHRpb25zYCAoT3B0aW9uYWwpIElmIHN0cmluZywgYXNzdW1lZCB0byBiZSB0aGUgYmFzZSBjaGFubmVsIHVybC4gSWYgb2JqZWN0LCBhc3N1bWVkIHRvIGJlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNvbnN0cnVjdG9yLlxuICAgICAqL1xuICAgIGdldENoYW5uZWw6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIC8vSWYgeW91IGp1c3Qgd2FudCB0byBwYXNzIGluIGEgc3RyaW5nXG4gICAgICAgIGlmIChvcHRpb25zICYmICEkLmlzUGxhaW5PYmplY3Qob3B0aW9ucykpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSB7XG4gICAgICAgICAgICAgICAgYmFzZTogb3B0aW9uc1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgICAgICB0cmFuc3BvcnQ6IHRoaXMuY29tZXRkXG4gICAgICAgIH07XG4gICAgICAgIHZhciBjaGFubmVsID0gbmV3IENoYW5uZWwoJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy5jaGFubmVsLCBkZWZhdWx0cywgb3B0aW9ucykpO1xuXG5cbiAgICAgICAgLy9XcmFwIHN1YnMgYW5kIHVuc3VicyBzbyB3ZSBjYW4gdXNlIGl0IHRvIHJlLWF0dGFjaCBoYW5kbGVycyBhZnRlciBiZWluZyBkaXNjb25uZWN0ZWRcbiAgICAgICAgdmFyIHN1YnMgPSBjaGFubmVsLnN1YnNjcmliZTtcbiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgc3ViaWQgPSBzdWJzLmFwcGx5KGNoYW5uZWwsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zICA9IHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuY29uY2F0KHN1YmlkKTtcbiAgICAgICAgICAgIHJldHVybiBzdWJpZDtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG5cbiAgICAgICAgdmFyIHVuc3VicyA9IGNoYW5uZWwudW5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwudW5zdWJzY3JpYmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcmVtb3ZlZCA9IHVuc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnNbaV0uaWQgPT09IHJlbW92ZWQuaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHJlbW92ZWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICpcbiAgICAgKiBTdXBwb3J0ZWQgZXZlbnRzIGFyZTogYGNvbm5lY3RgLCBgZGlzY29ubmVjdGAsIGBzdWJzY3JpYmVgLCBgdW5zdWJzY3JpYmVgLCBgcHVibGlzaGAsIGBlcnJvcmAuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqL1xuICAgIG9uOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vbi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdG9wIGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqL1xuICAgIG9mZjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub2ZmLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZXZlbnRzIGFuZCBleGVjdXRlIGhhbmRsZXJzLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqL1xuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBDaGFubmVsTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiAjIyBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlIEVwaWNlbnRlciBwbGF0Zm9ybSBwcm92aWRlcyBhIHB1c2ggY2hhbm5lbCwgd2hpY2ggYWxsb3dzIHlvdSB0byBwdWJsaXNoIGFuZCBzdWJzY3JpYmUgdG8gbWVzc2FnZXMgd2l0aGluIGEgW3Byb2plY3RdKC4uLy4uLy4uL2dsb3NzYXJ5LyNwcm9qZWN0cyksIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcyksIG9yIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS4gVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIGFyb3VuZCB0aGUgKG1vcmUgZ2VuZXJpYykgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLyksIHRvIGluc3RhbnRpYXRlIGl0IHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLiBJZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gaW5jbHVkaW5nIGEgbm90aWZpY2F0aW9uIG9yIGNoYXQgZmVhdHVyZSBpbiB5b3VyIHByb2plY3QsIHVzaW5nIGFuIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgcHJvYmFibHkgdGhlIGVhc2llc3Qgd2F5IHRvIGdldCBzdGFydGVkLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIuIFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLlxuICpcbiAqIFRvIHVzZSB0aGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcjogaW5zdGFudGlhdGUgaXQsIGdldCB0aGUgY2hhbm5lbCBvZiB0aGUgc2NvcGUgeW91IHdhbnQgKFt1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCksIG9yIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykpLCB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgdmFyIGdjID0gY20uZ2V0R3JvdXBDaGFubmVsKCk7XG4gKiAgICAgZ2Muc3Vic2NyaWJlKCdicm9hZGNhc3RzJywgY2FsbGJhY2spO1xuICpcbiAqIEZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gRXBpY2VudGVyJ3MgcHVzaCBjaGFubmVsLCBzZWUgdGhlIGludHJvZHVjdG9yeSBub3RlcyBvbiB0aGUgW1B1c2ggQ2hhbm5lbCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLykgcGFnZS5cbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGluY2x1ZGU6XG4gKlxuICogKiBgc2VydmVyYCBPYmplY3Qgd2l0aCBkZXRhaWxzIGFib3V0IHRoZSBFcGljZW50ZXIgcHJvamVjdCBmb3IgdGhpcyBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGluc3RhbmNlLlxuICogKiBgc2VydmVyLmFjY291bnRgIFRoZSBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBzZXJ2ZXIucHJvamVjdGAgRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKi9cblxudmFyIENoYW5uZWxNYW5hZ2VyID0gcmVxdWlyZSgnLi9jaGFubmVsLW1hbmFnZXInKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi91dGlsL2luaGVyaXQnKTtcbnZhciB1cmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcblxudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIHNlc3Npb24gPSBuZXcgQXV0aE1hbmFnZXIoKTtcbnZhciBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yID0gZnVuY3Rpb24gKHZhbHVlLCBzZXNzaW9uS2V5TmFtZSwgc2V0dGluZ3MpIHtcbiAgICBpZiAoIXZhbHVlKSB7XG4gICAgICAgIHZhciB1c2VySW5mbyA9IHNlc3Npb24uZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICBpZiAoc2V0dGluZ3MgJiYgc2V0dGluZ3Nbc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIGlmICh1c2VySW5mb1tzZXNzaW9uS2V5TmFtZV0pIHtcbiAgICAgICAgICAgIHZhbHVlID0gdXNlckluZm9bc2Vzc2lvbktleU5hbWVdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHNlc3Npb25LZXlOYW1lICsgJyBub3QgZm91bmQuIFBsZWFzZSBsb2ctaW4gYWdhaW4sIG9yIHNwZWNpZnkgJyArIHNlc3Npb25LZXlOYW1lICsgJyBleHBsaWNpdGx5Jyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHZhbHVlO1xufTtcbnZhciBfX3N1cGVyID0gQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlO1xudmFyIEVwaWNlbnRlckNoYW5uZWxNYW5hZ2VyID0gY2xhc3NGcm9tKENoYW5uZWxNYW5hZ2VyLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciB1c2VySW5mbyA9IHNlc3Npb24uZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuXG4gICAgICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgICAgIGFjY291bnQ6IHVzZXJJbmZvLmFjY291bnQsXG4gICAgICAgICAgICBwcm9qZWN0OiB1c2VySW5mby5wcm9qZWN0LFxuICAgICAgICB9O1xuICAgICAgICB2YXIgZGVmYXVsdENvbWV0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgdXNlckluZm8sIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciB1cmxPcHRzID0gdXJsU2VydmljZShkZWZhdWx0Q29tZXRPcHRpb25zLnNlcnZlcik7XG4gICAgICAgIGlmICghZGVmYXVsdENvbWV0T3B0aW9ucy51cmwpIHtcbiAgICAgICAgICAgIC8vRGVmYXVsdCBlcGljZW50ZXIgY29tZXRkIGVuZHBvaW50XG4gICAgICAgICAgICBkZWZhdWx0Q29tZXRPcHRpb25zLnVybCA9IHVybE9wdHMucHJvdG9jb2wgKyAnOi8vJyArIHVybE9wdHMuaG9zdCArICcvY2hhbm5lbC9zdWJzY3JpYmUnO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5vcHRpb25zID0gZGVmYXVsdENvbWV0T3B0aW9ucztcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBkZWZhdWx0Q29tZXRPcHRpb25zKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykuIFRoZSBncm91cCBtdXN0IGV4aXN0IGluIHRoZSBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdCBwcm92aWRlZC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBubyBub3RpZmljYXRpb25zIGZyb20gRXBpY2VudGVyIG9uIHRoaXMgY2hhbm5lbDsgYWxsIG1lc3NhZ2VzIGFyZSB1c2VyLW9yaWdpbmF0ZWQuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIGdjID0gY20uZ2V0R3JvdXBDaGFubmVsKCk7XG4gICAgICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRvIGJyb2FkY2FzdCB0by4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0R3JvdXBDaGFubmVsOiBmdW5jdGlvbiAoZ3JvdXBOYW1lKSB7XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJyk7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvZ3JvdXAnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWVdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgZ2l2ZW4gW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLlxuICAgICAqXG4gICAgICogVGhpcyBpcyB0eXBpY2FsbHkgdXNlZCB0b2dldGhlciB3aXRoIHRoZSBbV29ybGQgTWFuYWdlcl0oLi4vd29ybGQtbWFuYWdlcikuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB3b3JsZENoYW5uZWwgPSBjbS5nZXRXb3JsZENoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgd29ybGRDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB3b3JsZGAgVGhlIHdvcmxkIG9iamVjdCBvciBpZC5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgR3JvdXAgdGhlIHdvcmxkIGV4aXN0cyBpbi4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0V29ybGRDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuXG4gICAgICAgIHZhciBiYXNlVG9waWMgPSBbJy93b3JsZCcsIGFjY291bnQsIHByb2plY3QsIGdyb3VwTmFtZSwgd29ybGRpZF0uam9pbignLycpO1xuICAgICAgICByZXR1cm4gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBjdXJyZW50IFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpbiB0aGF0IHVzZXIncyBjdXJyZW50IFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLiBOb3RlIHRoYXQgdGhpcyBjaGFubmVsIG9ubHkgZ2V0cyBub3RpZmljYXRpb25zIGZvciB3b3JsZHMgY3VycmVudGx5IGluIG1lbW9yeS4gKFNlZSBtb3JlIGJhY2tncm91bmQgb24gW3BlcnNpc3RlbmNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UpLilcbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAqICAgICAgICAgcnVuOiB7IG1vZGVsOiAnbW9kZWwuZXFuJyB9XG4gICAgICogICAgIH0pO1xuICAgICAqICAgICB3b3JsZE1hbmFnZXIuZ2V0Q3VycmVudFdvcmxkKCkudGhlbihmdW5jdGlvbiAod29ybGRPYmplY3QsIHdvcmxkQWRhcHRlcikge1xuICAgICAqICAgICAgICAgdmFyIHVzZXJDaGFubmVsID0gY20uZ2V0VXNlckNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgdXNlckNoYW5uZWwuc3Vic2NyaWJlKCcnLCBmdW5jdGlvbiAoZGF0YSkge1xuICAgICAqICAgICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgICAqICAgICAgICAgfSk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFdvcmxkIG9iamVjdCBvciBpZC5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgdXNlcmAgKE9wdGlvbmFsKSBVc2VyIG9iamVjdCBvciBpZC4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCB1c2VyIGlkIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgR3JvdXAgdGhlIHdvcmxkIGV4aXN0cyBpbi4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0VXNlckNoYW5uZWw6IGZ1bmN0aW9uICh3b3JsZCwgdXNlciwgZ3JvdXBOYW1lKSB7XG4gICAgICAgIHZhciB3b3JsZGlkID0gKCQuaXNQbGFpbk9iamVjdCh3b3JsZCkgJiYgd29ybGQuaWQpID8gd29ybGQuaWQgOiB3b3JsZDtcbiAgICAgICAgaWYgKCF3b3JsZGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgd29ybGQgaWQnKTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgdXNlcmlkID0gKCQuaXNQbGFpbk9iamVjdCh1c2VyKSAmJiB1c2VyLmlkKSA/IHVzZXIuaWQgOiB1c2VyO1xuICAgICAgICB1c2VyaWQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKHVzZXJpZCwgJ3VzZXJJZCcpO1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScpO1xuXG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvdXNlcnMnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWQsIHVzZXJpZF0uam9pbignLycpO1xuICAgICAgICByZXR1cm4gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgdGhhdCBhdXRvbWF0aWNhbGx5IHRyYWNrcyB0aGUgcHJlc2VuY2Ugb2YgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGF0IGlzLCB3aGV0aGVyIHRoZSBlbmQgdXNlciBpcyBjdXJyZW50bHkgb25saW5lIGluIHRoaXMgZ3JvdXAgYW5kIHdvcmxkLiBOb3RpZmljYXRpb25zIGFyZSBhdXRvbWF0aWNhbGx5IHNlbnQgd2hlbiB0aGUgZW5kIHVzZXIgY29tZXMgb25saW5lLCBhbmQgd2hlbiB0aGUgZW5kIHVzZXIgZ29lcyBvZmZsaW5lIChub3QgcHJlc2VudCBmb3IgbW9yZSB0aGFuIDIgbWludXRlcykuIFVzZWZ1bCBpbiBtdWx0aXBsYXllciBnYW1lcyBmb3IgbGV0dGluZyBlYWNoIGVuZCB1c2VyIGtub3cgd2hldGhlciBvdGhlciB1c2VycyBpbiB0aGVpciBzaGFyZWQgd29ybGQgYXJlIGFsc28gb25saW5lLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgICogICAgIH0pO1xuICAgICAqICAgICB3b3JsZE1hbmFnZXIuZ2V0Q3VycmVudFdvcmxkKCkudGhlbihmdW5jdGlvbiAod29ybGRPYmplY3QsIHdvcmxkU2VydmljZSkge1xuICAgICAqICAgICAgICAgdmFyIHByZXNlbmNlQ2hhbm5lbCA9IGNtLmdldFByZXNlbmNlQ2hhbm5lbCh3b3JsZE9iamVjdCk7XG4gICAgICogICAgICAgICBwcmVzZW5jZUNoYW5uZWwub24oJ3ByZXNlbmNlJywgZnVuY3Rpb24gKGV2dCwgbm90aWZpY2F0aW9uKSB7XG4gICAgICogICAgICAgICAgICAgIGNvbnNvbGUubG9nKG5vdGlmaWNhdGlvbi5vbmxpbmUsIG5vdGlmaWNhdGlvbi51c2VySWQpO1xuICAgICAqICAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJpZGAgKE9wdGlvbmFsKSBVc2VyIG9iamVjdCBvciBpZC4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCB1c2VyIGlkIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgR3JvdXAgdGhlIHdvcmxkIGV4aXN0cyBpbi4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0UHJlc2VuY2VDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXJpZCwgZ3JvdXBOYW1lKSB7XG4gICAgICAgIHZhciB3b3JsZGlkID0gKCQuaXNQbGFpbk9iamVjdCh3b3JsZCkgJiYgd29ybGQuaWQpID8gd29ybGQuaWQgOiB3b3JsZDtcbiAgICAgICAgaWYgKCF3b3JsZGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgd29ybGQgaWQnKTtcbiAgICAgICAgfVxuICAgICAgICB1c2VyaWQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKHVzZXJpZCwgJ3VzZXJJZCcpO1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScpO1xuXG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvdXNlcnMnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcblxuICAgICAgICB2YXIgbGFzdFBpbmdUaW1lID0geyB9O1xuXG4gICAgICAgIHZhciBQSU5HX0lOVEVSVkFMID0gNjAwMDtcbiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIGZ1bmN0aW9uIChub3RpZmljYXRpb24pIHtcbiAgICAgICAgICAgIHZhciBpbmNvbWluZ1VzZXJJZCA9IG5vdGlmaWNhdGlvbi5kYXRhLnVzZXI7XG4gICAgICAgICAgICBpZiAoIWxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gJiYgaW5jb21pbmdVc2VySWQgIT09IHVzZXJpZCkge1xuICAgICAgICAgICAgICAgIGNoYW5uZWwudHJpZ2dlci5jYWxsKGNoYW5uZWwsICdwcmVzZW5jZScsIHsgdXNlcklkOiBpbmNvbWluZ1VzZXJJZCwgb25saW5lOiB0cnVlIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2luY29taW5nVXNlcklkXSA9IChuZXcgRGF0ZSgpKS52YWx1ZU9mKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHNldEludGVydmFsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGNoYW5uZWwucHVibGlzaCgnaW50ZXJuYWwtcGluZy1jaGFubmVsJywgeyB1c2VyOiB1c2VyaWQgfSk7XG5cbiAgICAgICAgICAgICQuZWFjaChsYXN0UGluZ1RpbWUsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vdyA9IChuZXcgRGF0ZSgpKS52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgaWYgKHZhbHVlICYmIHZhbHVlICsgKFBJTkdfSU5URVJWQUwgKiAyKSA8IG5vdykge1xuICAgICAgICAgICAgICAgICAgICBsYXN0UGluZ1RpbWVba2V5XSA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIGNoYW5uZWwudHJpZ2dlci5jYWxsKGNoYW5uZWwsICdwcmVzZW5jZScsIHsgdXNlcklkOiBrZXksIG9ubGluZTogZmFsc2UgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIFBJTkdfSU5URVJWQUwpO1xuXG4gICAgICAgIHJldHVybiBjaGFubmVsO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgZ2l2ZW4gY29sbGVjdGlvbi4gKFRoZSBjb2xsZWN0aW9uIG5hbWUgaXMgc3BlY2lmaWVkIGluIHRoZSBgcm9vdGAgYXJndW1lbnQgd2hlbiB0aGUgW0RhdGEgU2VydmljZV0oLi4vZGF0YS1hcGktc2VydmljZS8pIGlzIGluc3RhbnRpYXRlZC4pIE11c3QgYmUgb25lIG9mIHRoZSBjb2xsZWN0aW9ucyBpbiB0aGlzIGFjY291bnQgKHRlYW0pIGFuZCBwcm9qZWN0LlxuICAgICAqXG4gICAgICogVGhlcmUgYXJlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIGZyb20gRXBpY2VudGVyIG9uIHRoaXMgY2hhbm5lbCB3aGVuIGRhdGEgaXMgY3JlYXRlZCwgdXBkYXRlZCwgb3IgZGVsZXRlZCBpbiB0aGlzIGNvbGxlY3Rpb24uIFNlZSBtb3JlIG9uIFthdXRvbWF0aWMgbWVzc2FnZXMgdG8gdGhlIGRhdGEgY2hhbm5lbF0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvI2RhdGEtbWVzc2FnZXMpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciBnYyA9IGNtLmdldERhdGFDaGFubmVsKCdzdXJ2ZXktcmVzcG9uc2VzJyk7XG4gICAgICogICAgIGdjLnN1YnNjcmliZSgnJywgZnVuY3Rpb24oZGF0YSwgbWV0YSkge1xuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gbWV0YS5kYXRlIGlzIHRpbWUgb2YgY2hhbmdlLFxuICAgICAqICAgICAgICAgIC8vIG1ldGEuc3ViVHlwZSBpcyB0aGUga2luZCBvZiBjaGFuZ2U6IG5ldywgdXBkYXRlLCBvciBkZWxldGVcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnBhdGggaXMgdGhlIGZ1bGwgcGF0aCB0byB0aGUgY2hhbmdlZCBkYXRhXG4gICAgICogICAgICAgICAgY29uc29sZS5sb2cobWV0YSk7XG4gICAgICogICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBjb2xsZWN0aW9uYCBOYW1lIG9mIGNvbGxlY3Rpb24gd2hvc2UgYXV0b21hdGljIG5vdGlmaWNhdGlvbnMgeW91IHdhbnQgdG8gcmVjZWl2ZS5cbiAgICAgKi9cbiAgICBnZXREYXRhQ2hhbm5lbDogZnVuY3Rpb24gKGNvbGxlY3Rpb24pIHtcbiAgICAgICAgaWYgKCFjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgY29sbGVjdGlvbiB0byBsaXN0ZW4gb24uJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvZGF0YScsIGFjY291bnQsIHByb2plY3QsIGNvbGxlY3Rpb25dLmpvaW4oJy8nKTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcblxuICAgICAgICAvL1RPRE86IEZpeCBhZnRlciBFcGljZW50ZXIgYnVnIGlzIHJlc29sdmVkXG4gICAgICAgIHZhciBvbGRzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKHRvcGljLCBjYWxsYmFjaywgY29udGV4dCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNhbGxiYWNrV2l0aENsZWFuRGF0YSA9IGZ1bmN0aW9uIChwYXlsb2FkKSB7XG4gICAgICAgICAgICAgICAgdmFyIG1ldGEgPSB7XG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IHBheWxvYWQuY2hhbm5lbCxcbiAgICAgICAgICAgICAgICAgICAgc3ViVHlwZTogcGF5bG9hZC5kYXRhLnN1YlR5cGUsXG4gICAgICAgICAgICAgICAgICAgIGRhdGU6IHBheWxvYWQuZGF0YS5kYXRlXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgYWN0dWFsRGF0YSA9IHBheWxvYWQuZGF0YS5kYXRhO1xuICAgICAgICAgICAgICAgIGlmIChhY3R1YWxEYXRhLmRhdGEpIHsgLy9EZWxldGUgbm90aWZpY2F0aW9ucyBhcmUgb25lIGRhdGEtbGV2ZWwgYmVoaW5kIG9mIGNvdXJzZVxuICAgICAgICAgICAgICAgICAgICBhY3R1YWxEYXRhID0gYWN0dWFsRGF0YS5kYXRhO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNhbGxiYWNrLmNhbGwoY29udGV4dCwgYWN0dWFsRGF0YSwgbWV0YSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuIG9sZHN1YnMuY2FsbChjaGFubmVsLCB0b3BpYywgY2FsbGJhY2tXaXRoQ2xlYW5EYXRhLCBjb250ZXh0LCBvcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBFcGljZW50ZXJDaGFubmVsTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgRVBJX0NPT0tJRV9LRVk6ICdlcGljZW50ZXIucHJvamVjdC50b2tlbicsXG4gICAgRVBJX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLnVzZXIuc2Vzc2lvbicsXG4gICAgU1RSQVRFR1lfU0VTU0lPTl9LRVk6ICdlcGljZW50ZXItc2NlbmFyaW8nXG59OyIsIi8qKlxuKiAjIyBSdW4gTWFuYWdlclxuKlxuKiBUaGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGFjY2VzcyB0byBydW5zIGZvciB5b3VyIHByb2plY3QuIFRoaXMgYWxsb3dzIHlvdSB0byByZWFkIGFuZCB1cGRhdGUgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy4gQWRkaXRpb25hbGx5LCB0aGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGNvbnRyb2wgb3ZlciBydW4gY3JlYXRpb24gZGVwZW5kaW5nIG9uIHJ1biBzdGF0ZXMuIFNwZWNpZmljYWxseSwgeW91IGNhbiBzZWxlY3QgW3J1biBjcmVhdGlvbiBzdHJhdGVnaWVzIChydWxlcyldKC4uLy4uL3N0cmF0ZWd5LykgZm9yIHdoaWNoIHJ1bnMgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdCB3b3JrIHdpdGggd2hlbiB0aGV5IGxvZyBpbiB0byB5b3VyIHByb2plY3QuXG4qXG4qIFRoZXJlIGFyZSBtYW55IHdheXMgdG8gY3JlYXRlIG5ldyBydW5zLCBpbmNsdWRpbmcgdGhlIEVwaWNlbnRlci5qcyBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLCB0aGUgUkVTRlRmdWwgW1J1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaSkgYW5kIHRoZSBbTW9kZWwgUnVuIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL290aGVyX2FwaXMvbW9kZWxfYXBpcy9ydW4vKS4gSG93ZXZlciwgZm9yIHNvbWUgcHJvamVjdHMgaXQgbWFrZXMgbW9yZSBzZW5zZSB0byBwaWNrIHVwIHdoZXJlIHRoZSB1c2VyIGxlZnQgb2ZmLCB1c2luZyBhbiBleGlzdGluZyBydW4uIEFuZCBpbiBzb21lIHByb2plY3RzLCB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZSBpcyBjb25kaXRpb25hbCwgZm9yIGV4YW1wbGUgYmFzZWQgb24gY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBleGlzdGluZyBydW4gb3IgeW91ciBvd24ga25vd2xlZGdlIGFib3V0IHRoZSBtb2RlbC4gVGhlIFJ1biBNYW5hZ2VyIHByb3ZpZGVzIHRoaXMgbGV2ZWwgb2YgY29udHJvbDogeW91ciBjYWxsIHRvIGBnZXRSdW4oKWAsIHJhdGhlciB0aGFuIGFsd2F5cyByZXR1cm5pbmcgYSBuZXcgcnVuLCByZXR1cm5zIGEgcnVuIGJhc2VkIG9uIHRoZSBzdHJhdGVneSB5b3UndmUgc3BlY2lmaWVkLiAoTm90ZSB0aGF0IG1hbnkgb2YgdGhlIEVwaWNlbnRlciBzYW1wbGUgcHJvamVjdHMgdXNlIGEgUnVuIFNlcnZpY2UgZGlyZWN0bHksIGJlY2F1c2UgZ2VuZXJhbGx5IHRoZSBzYW1wbGUgcHJvamVjdHMgYXJlIHBsYXllZCBpbiBvbmUgZW5kIHVzZXIgc2Vzc2lvbiBhbmQgZG9uJ3QgY2FyZSBhYm91dCBydW4gc3RhdGVzIG9yIHJ1biBzdHJhdGVnaWVzLilcbipcbipcbiogIyMjIFVzaW5nIHRoZSBSdW4gTWFuYWdlciB0byBjcmVhdGUgYW5kIGFjY2VzcyBydW5zXG4qXG4qIFRvIHVzZSB0aGUgUnVuIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0IGJ5IHBhc3NpbmcgaW46XG4qXG4qICAgKiBgcnVuYDogKHJlcXVpcmVkKSBSdW4gb2JqZWN0LiBNdXN0IGNvbnRhaW46XG4qICAgICAgICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4qICAgICAgICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiogICAgICAgKiBgbW9kZWxgOiBUaGUgbmFtZSBvZiB5b3VyIHByaW1hcnkgbW9kZWwgZmlsZS4gKFNlZSBtb3JlIG9uIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pLilcbiogICAgICAgKiBgc2NvcGVgOiAob3B0aW9uYWwpIFNjb3BlIG9iamVjdCBmb3IgdGhlIHJ1biwgZm9yIGV4YW1wbGUgYHNjb3BlLmdyb3VwYCB3aXRoIHZhbHVlIG9mIHRoZSBuYW1lIG9mIHRoZSBncm91cC5cbiogICAgICAgKiBgc2VydmVyYDogKG9wdGlvbmFsKSBBbiBvYmplY3Qgd2l0aCBvbmUgZmllbGQsIGBob3N0YC4gVGhlIHZhbHVlIG9mIGBob3N0YCBpcyB0aGUgc3RyaW5nIGBhcGkuZm9yaW8uY29tYCwgdGhlIFVSSSBvZiB0aGUgRm9yaW8gc2VydmVyLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0LCBidXQgeW91IGNhbiBwYXNzIGl0IGV4cGxpY2l0bHkgaWYgZGVzaXJlZC4gSXQgaXMgbW9zdCBjb21tb25seSB1c2VkIGZvciBjbGFyaXR5IHdoZW4geW91IGFyZSBbaG9zdGluZyBhbiBFcGljZW50ZXIgcHJvamVjdCBvbiB5b3VyIG93biBzZXJ2ZXJdKC4uLy4uLy4uL2hvd190by9zZWxmX2hvc3RpbmcvKS5cbiogICAgICAgKiBgZmlsZXNgOiAob3B0aW9uYWwpIElmIGFuZCBvbmx5IGlmIHlvdSBhcmUgdXNpbmcgYSBWZW5zaW0gbW9kZWwgYW5kIHlvdSBoYXZlIGFkZGl0aW9uYWwgZGF0YSB0byBwYXNzIGluIHRvIHlvdXIgbW9kZWwsIHlvdSBjYW4gcGFzcyBhIGBmaWxlc2Agb2JqZWN0IHdpdGggdGhlIG5hbWVzIG9mIHRoZSBmaWxlcywgZm9yIGV4YW1wbGU6IGBcImZpbGVzXCI6IHtcImRhdGFcIjogXCJteUV4dHJhRGF0YS54bHNcIn1gLiAoTm90ZSB0aGF0IHlvdSdsbCBhbHNvIG5lZWQgdG8gYWRkIHRoaXMgc2FtZSBmaWxlcyBvYmplY3QgdG8geW91ciBWZW5zaW0gW2NvbmZpZ3VyYXRpb24gZmlsZV0oLi4vLi4vLi4vbW9kZWxfY29kZS92ZW5zaW0vKS4pIFNlZSB0aGUgW3VuZGVybHlpbmcgTW9kZWwgUnVuIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL290aGVyX2FwaXMvbW9kZWxfYXBpcy9ydW4vI3Bvc3QtY3JlYXRpbmctYS1uZXctcnVuLWZvci10aGlzLXByb2plY3QpIGZvciBhZGRpdGlvbmFsIGluZm9ybWF0aW9uLlxuKlxuKiAgICogYHN0cmF0ZWd5YDogKG9wdGlvbmFsKSBSdW4gY3JlYXRpb24gc3RyYXRlZ3kgZm9yIHdoZW4gdG8gY3JlYXRlIGEgbmV3IHJ1biBhbmQgd2hlbiB0byByZXVzZSBhbiBlbmQgdXNlcidzIGV4aXN0aW5nIHJ1bi4gU2VlIFtSdW4gTWFuYWdlciBTdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pIGZvciBkZXRhaWxzLiBEZWZhdWx0cyB0byBgbmV3LWlmLWluaXRpYWxpemVkYC5cbipcbiogICAqIGBzZXNzaW9uS2V5YDogKG9wdGlvbmFsKSBOYW1lIG9mIGJyb3dzZXIgY29va2llIGluIHdoaWNoIHRvIHN0b3JlIHJ1biBpbmZvcm1hdGlvbiwgaW5jbHVkaW5nIHJ1biBpZC4gTWFueSBjb25kaXRpb25hbCBzdHJhdGVnaWVzLCBpbmNsdWRpbmcgdGhlIHByb3ZpZGVkIHN0cmF0ZWdpZXMsIHJlbHkgb24gdGhpcyBicm93c2VyIGNvb2tpZSB0byBzdG9yZSB0aGUgcnVuIGlkIGFuZCBoZWxwIG1ha2UgdGhlIGRlY2lzaW9uIG9mIHdoZXRoZXIgdG8gY3JlYXRlIGEgbmV3IHJ1biBvciB1c2UgYW4gZXhpc3Rpbmcgb25lLiBUaGUgbmFtZSBvZiB0aGlzIGNvb2tpZSBkZWZhdWx0cyB0byBgZXBpY2VudGVyLXNjZW5hcmlvYCBhbmQgY2FuIGJlIHNldCB3aXRoIHRoZSBgc2Vzc2lvbktleWAgcGFyYW1ldGVyLlxuKlxuKlxuKiBBZnRlciBpbnN0YW50aWF0aW5nIGEgUnVuIE1hbmFnZXIsIG1ha2UgYSBjYWxsIHRvIGBnZXRSdW4oKWAgd2hlbmV2ZXIgeW91IG5lZWQgdG8gYWNjZXNzIGEgcnVuIGZvciB0aGlzIGVuZCB1c2VyLiBUaGUgYFJ1bk1hbmFnZXIucnVuYCBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFtSdW4gU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykuIFRoZSBSdW4gU2VydmljZSBhbGxvd3MgeW91IHRvIGFjY2VzcyB2YXJpYWJsZXMsIGNhbGwgb3BlcmF0aW9ucywgZXRjLlxuKlxuKiAqKkV4YW1wbGUqKlxuKlxuKiAgICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuKiAgICAgICAgICAgcnVuOiB7XG4qICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgICAgICAgbW9kZWw6ICdzdXBwbHktY2hhaW4tbW9kZWwuamwnLFxuKiAgICAgICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuKiAgICAgICAgICAgfSxcbiogICAgICAgICAgIHN0cmF0ZWd5OiAnYWx3YXlzLW5ldycsXG4qICAgICAgICAgICBzZXNzaW9uS2V5OiAnZXBpY2VudGVyLXNlc3Npb24nXG4qICAgICAgIH0pO1xuKiAgICAgICBybS5nZXRSdW4oKVxuKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuKSB7XG4qICAgICAgICAgICAgICAgLy8gdGhlIHJldHVybiB2YWx1ZSBvZiBnZXRSdW4oKSBpcyBhIHJ1biBvYmplY3RcbiogICAgICAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuKiAgICAgICAgICAgICAgIC8vIHRoZSBSdW5NYW5hZ2VyLnJ1biBhbHNvIGNvbnRhaW5zIHRoZSBpbnN0YW50aWF0ZWQgUnVuIFNlcnZpY2UsXG4qICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4qICAgICAgICAgICAgICAgcm0ucnVuLmRvKCdydW5Nb2RlbCcpO1xuKiAgICAgICB9KVxuKlxuKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHN0cmF0ZWdpZXNNYXAgPSByZXF1aXJlKCcuL3J1bi1zdHJhdGVnaWVzL3N0cmF0ZWdpZXMtbWFwJyk7XG52YXIgc3BlY2lhbE9wZXJhdGlvbnMgPSByZXF1aXJlKCcuL3NwZWNpYWwtb3BlcmF0aW9ucycpO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG5cbmZ1bmN0aW9uIHBhdGNoUnVuU2VydmljZShzZXJ2aWNlLCBtYW5hZ2VyKSB7XG4gICAgaWYgKHNlcnZpY2UucGF0Y2hlZCkge1xuICAgICAgICByZXR1cm4gc2VydmljZTtcbiAgICB9XG5cbiAgICB2YXIgb3JpZyA9IHNlcnZpY2UuZG87XG4gICAgc2VydmljZS5kbyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YXIgcmVzZXJ2ZWRPcHMgPSBPYmplY3Qua2V5cyhzcGVjaWFsT3BlcmF0aW9ucyk7XG4gICAgICAgIGlmIChyZXNlcnZlZE9wcy5pbmRleE9mKG9wZXJhdGlvbikgPT09IC0xKSB7XG4gICAgICAgICAgICByZXR1cm4gb3JpZy5hcHBseShzZXJ2aWNlLCBhcmd1bWVudHMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHNwZWNpYWxPcGVyYXRpb25zW29wZXJhdGlvbl0uY2FsbChzZXJ2aWNlLCBwYXJhbXMsIG9wdGlvbnMsIG1hbmFnZXIpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHNlcnZpY2UucGF0Y2hlZCA9IHRydWU7XG5cbiAgICByZXR1cm4gc2VydmljZTtcbn1cblxuXG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBSdW4gY3JlYXRpb24gc3RyYXRlZ3kgZm9yIHdoZW4gdG8gY3JlYXRlIGEgbmV3IHJ1biBhbmQgd2hlbiB0byByZXVzZSBhbiBlbmQgdXNlcidzIGV4aXN0aW5nIHJ1bi4gU2VlIFtSdW4gTWFuYWdlciBTdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pIGZvciBkZXRhaWxzLiBEZWZhdWx0cyB0byBgbmV3LWlmLWluaXRpYWxpemVkYC5cbiAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAqL1xuXG4gICAgc3RyYXRlZ3k6ICduZXctaWYtaW5pdGlhbGl6ZWQnXG59O1xuXG5mdW5jdGlvbiBSdW5NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5ydW4gaW5zdGFuY2VvZiBSdW5TZXJ2aWNlKSB7XG4gICAgICAgIHRoaXMucnVuID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnJ1biA9IG5ldyBSdW5TZXJ2aWNlKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH1cblxuICAgIHBhdGNoUnVuU2VydmljZSh0aGlzLnJ1biwgdGhpcyk7XG5cbiAgICB2YXIgU3RyYXRlZ3lDdG9yID0gdHlwZW9mIHRoaXMub3B0aW9ucy5zdHJhdGVneSA9PT0gJ2Z1bmN0aW9uJyA/IHRoaXMub3B0aW9ucy5zdHJhdGVneSA6IHN0cmF0ZWdpZXNNYXBbdGhpcy5vcHRpb25zLnN0cmF0ZWd5XTtcblxuICAgIGlmICghU3RyYXRlZ3lDdG9yKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignU3BlY2lmaWVkIHJ1biBjcmVhdGlvbiBzdHJhdGVneSB3YXMgaW52YWxpZDonLCB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kpO1xuICAgIH1cblxuICAgIHRoaXMuc3RyYXRlZ3kgPSBuZXcgU3RyYXRlZ3lDdG9yKHRoaXMucnVuLCB0aGlzLm9wdGlvbnMpO1xufVxuXG5SdW5NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBydW4gb2JqZWN0IGZvciBhICdnb29kJyBydW4uXG4gICAgICpcbiAgICAgKiBBIGdvb2QgcnVuIGlzIGRlZmluZWQgYnkgdGhlIHN0cmF0ZWd5LiBGb3IgZXhhbXBsZSwgaWYgdGhlIHN0cmF0ZWd5IGlzIGBhbHdheXMtbmV3YCwgdGhlIGNhbGxcbiAgICAgKiB0byBgZ2V0UnVuKClgIGFsd2F5cyByZXR1cm5zIGEgbmV3bHkgY3JlYXRlZCBydW47IGlmIHRoZSBzdHJhdGVneSBpcyBgbmV3LWlmLXBlcnNpc3RlZGAsXG4gICAgICogYGdldFJ1bigpYCBjcmVhdGVzIGEgbmV3IHJ1biBpZiB0aGUgcHJldmlvdXMgcnVuIGlzIGluIGEgcGVyc2lzdGVkIHN0YXRlLCBvdGhlcndpc2VcbiAgICAgKiBpdCByZXR1cm5zIHRoZSBwcmV2aW91cyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgbW9yZSBvbiBzdHJhdGVnaWVzLlxuICAgICAqXG4gICAgICogICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHJtLmdldFJ1bigpLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAqICAgICAgICAgIC8vIHVzZSB0aGUgcnVuIG9iamVjdFxuICAgICAqICAgICAgICAgIHZhciB0aGlzUnVuSWQgPSBydW4uaWQ7XG4gICAgICpcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIFJ1biBTZXJ2aWNlIG9iamVjdFxuICAgICAqICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogQHJldHVybiB7JHByb21pc2V9IFByb21pc2UgdG8gY29tcGxldGUgdGhlIGNhbGwuXG4gICAgICovXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5XG4gICAgICAgICAgICAgICAgLmdldFJ1bigpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBydW4gb2JqZWN0IGZvciBhIG5ldyBydW4sIHJlZ2FyZGxlc3Mgb2Ygc3RyYXRlZ3k6IGZvcmNlIGNyZWF0aW9uIG9mIGEgbmV3IHJ1bi5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5yZXNldCgpLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAqICAgICAgICAgIC8vIHVzZSB0aGUgKG5ldykgcnVuIG9iamVjdFxuICAgICAqICAgICAgICAgIHZhciB0aGlzUnVuSWQgPSBydW4uaWQ7XG4gICAgICpcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIFJ1biBTZXJ2aWNlIG9iamVjdFxuICAgICAqICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gYHJ1blNlcnZpY2VPcHRpb25zYCBUaGUgb3B0aW9ucyBvYmplY3QgdG8gY29uZmlndXJlIHRoZSBSdW4gU2VydmljZS4gU2VlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pIGZvciBtb3JlLlxuICAgICAqL1xuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RyYXRlZ3kucmVzZXQocnVuU2VydmljZU9wdGlvbnMpO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUnVuTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gYWx3YXlzIGNyZWF0ZSBhIG5ldyBydW4hXG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgbWFrZVNlcSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvbWFrZS1zZXF1ZW5jZScpO1xudmFyIEJhc2UgPSByZXF1aXJlKCcuL2lkZW50aXR5LXN0cmF0ZWd5Jyk7XG52YXIgU2Vzc2lvblN0b3JlID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIFVybFNlcnZpY2UgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBzZXNzaW9uU3RvcmUgPSBuZXcgU2Vzc2lvblN0b3JlKHt9KTtcbnZhciB1cmxTZXJ2aWNlID0gbmV3IFVybFNlcnZpY2UoKTtcbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc2Vzc2lvbktleToga2V5TmFtZXMuU1RSQVRFR1lfU0VTU0lPTl9LRVksXG4gICAgcGF0aDogJydcbn07XG5cbmZ1bmN0aW9uIHNldFJ1bkluU2Vzc2lvbihzZXNzaW9uS2V5LCBydW4sIHBhdGgpIHtcbiAgICBpZiAoIXBhdGgpIHtcbiAgICAgICAgaWYgKCF1cmxTZXJ2aWNlLmlzTG9jYWxob3N0KCkpIHtcbiAgICAgICAgICAgIHBhdGggPSAnLycgKyBbdXJsU2VydmljZS5hcHBQYXRoLCB1cmxTZXJ2aWNlLmFjY291bnRQYXRoLCB1cmxTZXJ2aWNlLnByb2plY3RQYXRoXS5qb2luKCcvJyk7XG4gICAgICAgICAgICAvLyBtYWtlIHN1cmUgd2UgZG9uJ3QgZ2V0IGNvbnNlY3V0ZWl2ZSAnLycgc28gd2UgaGF2ZSBhIHZhbGlkIHBhdGggZm9yIHRoZSBzZXNzaW9uXG4gICAgICAgICAgICBwYXRoID0gcGF0aC5yZXBsYWNlKC9cXC97Mix9L2csJy8nKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHBhdGggPSAnJztcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBzZXQgdGhlIHNlZXNpb25LZXkgZm9yIHRoZSBydW5cbiAgICBzZXNzaW9uU3RvcmUuc2V0KHNlc3Npb25LZXksIEpTT04uc3RyaW5naWZ5KHsgcnVuSWQ6IHJ1bi5pZCB9KSwgeyByb290OiBwYXRoIH0pO1xufVxuXG4vKipcbiogQ29uZGl0aW9uYWwgQ3JlYXRpb24gU3RyYXRlZ3lcbiogVGhpcyBzdHJhdGVneSB3aWxsIHRyeSB0byBnZXQgdGhlIHJ1biBzdG9yZWQgaW4gdGhlIGNvb2tpZSBhbmRcbiogZXZhbHVhdGUgaWYgbmVlZHMgdG8gY3JlYXRlIGEgbmV3IHJ1biBieSBjYWxsaW5nIHRoZSAnY29uZGl0aW9uJyBmdW5jdGlvblxuKi9cblxuLyoganNoaW50IGVxbnVsbDogdHJ1ZSAqL1xudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gU3RyYXRlZ3kocnVuU2VydmljZSwgY29uZGl0aW9uLCBvcHRpb25zKSB7XG5cbiAgICAgICAgaWYgKGNvbmRpdGlvbiA9PSBudWxsKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvbmRpdGlvbmFsIHN0cmF0ZWd5IG5lZWRzIGEgY29uZGl0aW9uIHRvIGNyZWF0ZXRlIGEgcnVuJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMucnVuID0gbWFrZVNlcShydW5TZXJ2aWNlKTtcbiAgICAgICAgdGhpcy5jb25kaXRpb24gPSB0eXBlb2YgY29uZGl0aW9uICE9PSAnZnVuY3Rpb24nID8gZnVuY3Rpb24gKCkgeyByZXR1cm4gY29uZGl0aW9uOyB9IDogY29uZGl0aW9uO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnJ1bk9wdGlvbnMgPSB0aGlzLm9wdGlvbnMucnVuO1xuICAgIH0sXG5cbiAgICBydW5PcHRpb25zV2l0aFNjb3BlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1c2VyU2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICByZXR1cm4gJC5leHRlbmQoe1xuICAgICAgICAgICAgc2NvcGU6IHsgZ3JvdXA6IHVzZXJTZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIG9wdCA9IHRoaXMucnVuT3B0aW9uc1dpdGhTY29wZSgpO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1blxuICAgICAgICAgICAgICAgIC5jcmVhdGUob3B0LCBydW5TZXJ2aWNlT3B0aW9ucylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oX3RoaXMub3B0aW9ucy5zZXNzaW9uS2V5LCBydW4sIF90aGlzLm9wdGlvbnMucGF0aCk7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5zdGFydCgpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJ1blNlc3Npb24gPSBKU09OLnBhcnNlKHNlc3Npb25TdG9yZS5nZXQodGhpcy5vcHRpb25zLnNlc3Npb25LZXkpKTtcblxuICAgICAgICBpZiAocnVuU2Vzc2lvbiAmJiBydW5TZXNzaW9uLnJ1bklkKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fbG9hZEFuZENoZWNrKHJ1blNlc3Npb24pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVzZXQoKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVuU2Vzc2lvbikge1xuICAgICAgICB2YXIgc2hvdWxkQ3JlYXRlID0gZmFsc2U7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAubG9hZChydW5TZXNzaW9uLnJ1bklkLCBudWxsLCB7XG4gICAgICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIHNob3VsZENyZWF0ZSA9IF90aGlzLmNvbmRpdGlvbi5jYWxsKF90aGlzLCBydW4sIGhlYWRlcnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNob3VsZENyZWF0ZSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgb3B0ID0gX3RoaXMucnVuT3B0aW9uc1dpdGhTY29wZSgpO1xuICAgICAgICAgICAgICAgICAgICAvLyB3ZSBuZWVkIHRvIGRvIHRoaXMsIG9uIHRoZSBvcmlnaW5hbCBydW5TZXJ2aWNlIChpZSBub3Qgc2VxdWVuY2lhbGl6ZWQpXG4gICAgICAgICAgICAgICAgICAgIC8vIHNvIHdlIGRvbid0IGdldCBpbiB0aGUgbWlkZGxlIG9mIHRoZSBxdWV1ZVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gX3RoaXMucnVuLm9yaWdpbmFsLmNyZWF0ZShvcHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFJ1bkluU2Vzc2lvbihfdGhpcy5vcHRpb25zLnNlc3Npb25LZXksIHJ1bik7XG4gICAgICAgICAgICAgICAgICAgICAgICBydW4uZnJlc2hseUNyZWF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIEJhc2UgPSB7fTtcblxuLy8gSW50ZXJmYWNlIHRoYXQgYWxsIHN0cmF0ZWdpZXMgbmVlZCB0byBpbXBsZW1lbnRcbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlICA9IHJ1blNlcnZpY2U7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIHJldHVybiBhIG5ld2x5IGNyZWF0ZWQgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSgpLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIHJldHVybiBhIHVzYWJsZSBydW5cbiAgICAgICAgcmV0dXJuICQuRGVmZXJyZWQoKS5yZXNvbHZlKHRoaXMucnVuU2VydmljZSkucHJvbWlzZSgpO1xuICAgIH1cbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG5cbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFdvcmxkQXBpQWRhcHRlciA9IHJlcXVpcmUoJy4uLy4uL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuXG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSA9IHJ1blNlcnZpY2U7XG4gICAgICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgICAgIHRoaXMuX2F1dGggPSBuZXcgQXV0aE1hbmFnZXIoKTtcbiAgICAgICAgdGhpcy5fbG9hZFJ1biA9IHRoaXMuX2xvYWRSdW4uYmluZCh0aGlzKTtcbiAgICAgICAgdGhpcy53b3JsZEFwaSA9IG5ldyBXb3JsZEFwaUFkYXB0ZXIodGhpcy5vcHRpb25zLnJ1bik7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgdmFyIGN1ckdyb3VwTmFtZSA9IHNlc3Npb24uZ3JvdXBOYW1lO1xuXG4gICAgICAgIHJldHVybiB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLndvcmxkQXBpLm5ld1J1bkZvcldvcmxkKHdvcmxkLmlkKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgdmFyIHdvcmxkQXBpID0gdGhpcy53b3JsZEFwaTtcbiAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLm1vZGVsO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuXG4gICAgICAgIGlmICghY3VyVXNlcklkKSB7XG4gICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCh7IHN0YXR1c0NvZGU6IDQwMCwgZXJyb3I6ICdXZSBuZWVkIGFuIGF1dGhlbnRpY2F0ZWQgdXNlciB0byBqb2luIGEgbXVsdGlwbGF5ZXIgd29ybGQuIChFUlI6IG5vIHVzZXJJZCBpbiBzZXNzaW9uKScgfSwgc2Vzc2lvbikucHJvbWlzZSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGxvYWRSdW5Gcm9tV29ybGQgPSBmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCh7IHN0YXR1c0NvZGU6IDQwNCwgZXJyb3I6ICdUaGUgdXNlciBpcyBub3QgaW4gYW55IHdvcmxkLicgfSwgeyBvcHRpb25zOiB0aGlzLm9wdGlvbnMsIHNlc3Npb246IHNlc3Npb24gfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50UnVuSWQoeyBtb2RlbDogbW9kZWwsIGZpbHRlcjogd29ybGQuaWQgfSlcbiAgICAgICAgICAgICAgICAudGhlbihfdGhpcy5fbG9hZFJ1bilcbiAgICAgICAgICAgICAgICAudGhlbihkdGQucmVzb2x2ZSlcbiAgICAgICAgICAgICAgICAuZmFpbChkdGQucmVqZWN0KTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgc2VydmVyRXJyb3IgPSBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgIC8vIGlzIHRoaXMgcG9zc2libGU/XG4gICAgICAgICAgICBkdGQucmVqZWN0KGVycm9yLCBzZXNzaW9uLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMud29ybGRBcGlcbiAgICAgICAgICAgIC5nZXRDdXJyZW50V29ybGRGb3JVc2VyKGN1clVzZXJJZCwgY3VyR3JvdXBOYW1lKVxuICAgICAgICAgICAgLnRoZW4obG9hZFJ1bkZyb21Xb3JsZClcbiAgICAgICAgICAgIC5mYWlsKHNlcnZlckVycm9yKTtcblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW5TZXJ2aWNlLmxvYWQoaWQsIG51bGwsIG9wdGlvbnMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCcgfHwgcnVuLmluaXRpYWxpemVkO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgQ29uZGl0aW9uYWxTdHJhdGVneSA9IHJlcXVpcmUoJy4vY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3knKTtcblxudmFyIF9fc3VwZXIgPSBDb25kaXRpb25hbFN0cmF0ZWd5LnByb3RvdHlwZTtcblxuLypcbiogIGNyZWF0ZSBhIG5ldyBydW4gb25seSBpZiBub3RoaW5nIGlzIHN0b3JlZCBpbiB0aGUgY29va2llXG4qICB0aGlzIGlzIHVzZWZ1bCBmb3IgYmFzZVJ1bnMuXG4qL1xudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKENvbmRpdGlvbmFsU3RyYXRlZ3ksIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgX19zdXBlci5jb25zdHJ1Y3Rvci5jYWxsKHRoaXMsIHJ1blNlcnZpY2UsIHRoaXMuY3JlYXRlSWYsIG9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICBjcmVhdGVJZjogZnVuY3Rpb24gKHJ1biwgaGVhZGVycykge1xuICAgICAgICAvLyBpZiB3ZSBhcmUgaGVyZSwgaXQgbWVhbnMgdGhhdCB0aGUgcnVuIGV4aXN0cy4uLiBzbyB3ZSBkb24ndCBuZWVkIGEgbmV3IG9uZVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgQ29uZGl0aW9uYWxTdHJhdGVneSA9IHJlcXVpcmUoJy4vY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3knKTtcblxudmFyIF9fc3VwZXIgPSBDb25kaXRpb25hbFN0cmF0ZWd5LnByb3RvdHlwZTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKENvbmRpdGlvbmFsU3RyYXRlZ3ksIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgX19zdXBlci5jb25zdHJ1Y3Rvci5jYWxsKHRoaXMsIHJ1blNlcnZpY2UsIHRoaXMuY3JlYXRlSWYsIG9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICBjcmVhdGVJZjogZnVuY3Rpb24gKHJ1biwgaGVhZGVycykge1xuICAgICAgICByZXR1cm4gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIElkZW50aXR5U3RyYXRlZ3kgPSByZXF1aXJlKCcuL2lkZW50aXR5LXN0cmF0ZWd5Jyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi8uLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgU3RhdGVBcGkgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGtleU5hbWVzID0gcmVxdWlyZSgnLi4va2V5LW5hbWVzJyk7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICBzdG9yZToge1xuICAgICAgICBzeW5jaHJvbm91czogdHJ1ZVxuICAgIH1cbn07XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShJZGVudGl0eVN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW4gPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnJ1bk9wdGlvbnMgPSB0aGlzLm9wdGlvbnMucnVuO1xuICAgICAgICB0aGlzLl9zdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh0aGlzLm9wdGlvbnMuc3RvcmUpO1xuICAgICAgICB0aGlzLnN0YXRlQXBpID0gbmV3IFN0YXRlQXBpKCk7XG4gICAgICAgIHRoaXMuX2F1dGggPSBuZXcgQXV0aE1hbmFnZXIoKTtcblxuICAgICAgICB0aGlzLl9sb2FkQW5kQ2hlY2sgPSB0aGlzLl9sb2FkQW5kQ2hlY2suYmluZCh0aGlzKTtcbiAgICAgICAgdGhpcy5fcmVzdG9yZVJ1biA9IHRoaXMuX3Jlc3RvcmVSdW4uYmluZCh0aGlzKTtcbiAgICAgICAgdGhpcy5fZ2V0QWxsUnVucyA9IHRoaXMuX2dldEFsbFJ1bnMuYmluZCh0aGlzKTtcbiAgICAgICAgdGhpcy5fbG9hZFJ1biA9IHRoaXMuX2xvYWRSdW4uYmluZCh0aGlzKTtcbiAgICB9LFxuXG4gICAgcmVzZXQ6IGZ1bmN0aW9uIChydW5TZXJ2aWNlT3B0aW9ucykge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQoe1xuICAgICAgICAgICAgc2NvcGU6IHsgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lIH1cbiAgICAgICAgfSwgdGhpcy5ydW5PcHRpb25zKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5ydW5cbiAgICAgICAgICAgIC5jcmVhdGUob3B0LCBydW5TZXJ2aWNlT3B0aW9ucylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICBydW4uZnJlc2hseUNyZWF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRBbGxSdW5zKClcbiAgICAgICAgICAgIC50aGVuKHRoaXMuX2xvYWRBbmRDaGVjayk7XG4gICAgfSxcblxuICAgIF9nZXRBbGxSdW5zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZSh0aGlzLl9zdG9yZS5nZXQoa2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZKSB8fCAne30nKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuLnF1ZXJ5KHtcbiAgICAgICAgICAgICd1c2VyLmlkJzogc2Vzc2lvbi51c2VySWQgfHwgJzAwMDAnLFxuICAgICAgICAgICAgJ3Njb3BlLmdyb3VwJzogc2Vzc2lvbi5ncm91cE5hbWVcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9sb2FkQW5kQ2hlY2s6IGZ1bmN0aW9uIChydW5zKSB7XG4gICAgICAgIGlmICghcnVucyB8fCAhcnVucy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZGF0ZUNvbXAgPSBmdW5jdGlvbiAoYSwgYikgeyByZXR1cm4gbmV3IERhdGUoYi5kYXRlKSAtIG5ldyBEYXRlKGEuZGF0ZSk7IH07XG4gICAgICAgIHZhciBsYXRlc3RSdW4gPSBydW5zLnNvcnQoZGF0ZUNvbXApWzBdO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgc2hvdWxkUmVwbGF5ID0gZmFsc2U7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuLmxvYWQobGF0ZXN0UnVuLmlkLCBudWxsLCB7XG4gICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAocnVuLCBtc2csIGhlYWRlcnMpIHtcbiAgICAgICAgICAgICAgICBzaG91bGRSZXBsYXkgPSBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgIHJldHVybiBzaG91bGRSZXBsYXkgPyBfdGhpcy5fcmVzdG9yZVJ1bihydW4uaWQpIDogcnVuO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX3Jlc3RvcmVSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZUFwaS5yZXBsYXkoeyBydW5JZDogcnVuSWQgfSlcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXNwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLl9sb2FkUnVuKHJlc3AucnVuKTtcbiAgICAgICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZFJ1bjogZnVuY3Rpb24gKGlkLCBvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwibW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgJ25ldy1pZi1pbml0aWFsaXplZCc6IHJlcXVpcmUoJy4vbmV3LWlmLWluaXRpYWxpemVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1wZXJzaXN0ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3knKSxcbiAgICAnbmV3LWlmLW1pc3NpbmcnOiByZXF1aXJlKCcuL25ldy1pZi1taXNzaW5nLXN0cmF0ZWd5JyksXG4gICAgJ2Fsd2F5cy1uZXcnOiByZXF1aXJlKCcuL2Fsd2F5cy1uZXctc3RyYXRlZ3knKSxcbiAgICAnbXVsdGlwbGF5ZXInOiByZXF1aXJlKCcuL211bHRpcGxheWVyLXN0cmF0ZWd5JyksXG4gICAgJ3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllcic6IHJlcXVpcmUoJy4vcGVyc2lzdGVudC1zaW5nbGUtcGxheWVyLXN0cmF0ZWd5JyksXG4gICAgJ25vbmUnOiByZXF1aXJlKCcuL2lkZW50aXR5LXN0cmF0ZWd5Jylcbn07XG4iLCIndXNlIHN0cmljdCc7XG52YXIgUnVuU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICB2YWxpZEZpbHRlcjogeyBzYXZlZDogdHJ1ZSB9XG59O1xuXG5mdW5jdGlvbiBTY2VuYXJpb01hbmFnZXIob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgdGhpcy5ydW5TZXJ2aWNlID0gdGhpcy5vcHRpb25zLnJ1biB8fCBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMpO1xufVxuXG5TY2VuYXJpb01hbmFnZXIucHJvdG90eXBlID0ge1xuICAgIGdldFJ1bnM6IGZ1bmN0aW9uIChmaWx0ZXIpIHtcbiAgICAgICAgdGhpcy5maWx0ZXIgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5vcHRpb25zLnZhbGlkRmlsdGVyLCBmaWx0ZXIpO1xuICAgICAgICByZXR1cm4gdGhpcy5ydW5TZXJ2aWNlLnF1ZXJ5KHRoaXMuZmlsdGVyKTtcbiAgICB9LFxuXG4gICAgbG9hZFZhcmlhYmxlczogZnVuY3Rpb24gKHZhcnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlciwgeyBpbmNsdWRlOiB2YXJzIH0pO1xuICAgIH0sXG5cbiAgICBzYXZlOiBmdW5jdGlvbiAocnVuLCBtZXRhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSgkLmV4dGVuZCh0cnVlLCB7fSwgeyBzYXZlZDogdHJ1ZSB9LCBtZXRhKSk7XG4gICAgfSxcblxuICAgIGFyY2hpdmU6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2dldFNlcnZpY2UocnVuKS5zYXZlKHsgc2F2ZWQ6IGZhbHNlIH0pO1xuICAgIH0sXG5cbiAgICBfZ2V0U2VydmljZTogZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICBpZiAodHlwZW9mIHJ1biA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgUnVuU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgIHRoaXMub3B0aW9ucywgeyBmaWx0ZXI6IHJ1biB9KSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHJ1biA9PT0gJ29iamVjdCcgJiYgcnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignU2F2ZSBtZXRob2QgcmVxdWlyZXMgYSBydW4gc2VydmljZSBvciBhIHJ1bklkJyk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKHJ1bklkKSB7XG4gICAgICAgIHJldHVybiBuZXcgUnVuU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgIHRoaXMub3B0aW9ucywgeyBmaWx0ZXI6IHJ1bklkIH0pKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNjZW5hcmlvTWFuYWdlcjtcblxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHJlc2V0OiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKSB7XG4gICAgICAgIHJldHVybiBtYW5hZ2VyLnJlc2V0KG9wdGlvbnMpO1xuICAgIH1cbn07XG4iLCIvKipcbiogIyMgV29ybGQgTWFuYWdlclxuKlxuKiBBcyBkaXNjdXNzZWQgdW5kZXIgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKSwgYSBbcnVuXSguLi8uLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgZW5kIHVzZXIgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwuIEZvciBidWlsZGluZyBtdWx0aXBsYXllciBzaW11bGF0aW9ucyB5b3UgdHlwaWNhbGx5IHdhbnQgbXVsdGlwbGUgZW5kIHVzZXJzIHRvIHNoYXJlIHRoZSBzYW1lIHNldCBvZiBpbnRlcmFjdGlvbnMsIGFuZCB3b3JrIHdpdGhpbiBhIGNvbW1vbiBzdGF0ZS4gRXBpY2VudGVyIGFsbG93cyB5b3UgdG8gY3JlYXRlIFwid29ybGRzXCIgdG8gaGFuZGxlIHN1Y2ggY2FzZXMuXG4qXG4qIFRoZSBXb3JsZCBNYW5hZ2VyIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIHRyYWNrIGFuZCBhY2Nlc3MgdGhlIGN1cnJlbnQgd29ybGQgYW5kIHJ1biBmb3IgcGFydGljdWxhciBlbmQgdXNlcnMuIEl0IGlzIHR5cGljYWxseSB1c2VkIGluIHBhZ2VzIHRoYXQgZW5kIHVzZXJzIHdpbGwgaW50ZXJhY3Qgd2l0aC4gKFRoZSByZWxhdGVkIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKSBoYW5kbGVzIGNyZWF0aW5nIG11bHRpcGxheWVyIHdvcmxkcywgYW5kIGFkZGluZyBhbmQgcmVtb3ZpbmcgZW5kIHVzZXJzIGFuZCBydW5zIGZyb20gYSB3b3JsZC4gQmVjYXVzZSBvZiB0aGlzLCB0eXBpY2FsbHkgdGhlIFdvcmxkIEFkYXB0ZXIgaXMgdXNlZCBmb3IgZmFjaWxpdGF0b3IgcGFnZXMgaW4geW91ciBwcm9qZWN0LilcbipcbiogIyMjIFVzaW5nIHRoZSBXb3JsZCBNYW5hZ2VyXG4qXG4qIFRvIHVzZSB0aGUgV29ybGQgTWFuYWdlciwgaW5zdGFudGlhdGUgaXQuIFRoZW4sIG1ha2UgY2FsbHMgdG8gYW55IG9mIHRoZSBtZXRob2RzIHlvdSBuZWVkLlxuKlxuKiBXaGVuIHlvdSBpbnN0YW50aWF0ZSBhIFdvcmxkIE1hbmFnZXIsIHRoZSB3b3JsZCdzIGFjY291bnQgaWQsIHByb2plY3QgaWQsIGFuZCBncm91cCBhcmUgYXV0b21hdGljYWxseSB0YWtlbiBmcm9tIHRoZSBzZXNzaW9uICh0aGFua3MgdG8gdGhlIFtBdXRoZW50aWNhdGlvbiBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlKSkuXG4qXG4qIE5vdGUgdGhhdCB0aGUgV29ybGQgTWFuYWdlciBkb2VzICpub3QqIGNyZWF0ZSB3b3JsZHMgYXV0b21hdGljYWxseS4gKFRoaXMgaXMgZGlmZmVyZW50IHRoYW4gdGhlIFtSdW4gTWFuYWdlcl0oLi4vcnVuLW1hbmFnZXIpLikgSG93ZXZlciwgeW91IGNhbiBwYXNzIGluIHNwZWNpZmljIG9wdGlvbnMgdG8gYW55IHJ1bnMgY3JlYXRlZCBieSB0aGUgbWFuYWdlciwgdXNpbmcgYSBgcnVuYCBvYmplY3QuXG4qXG4qIFRoZSBwYXJhbWV0ZXJzIGZvciBjcmVhdGluZyBhIFdvcmxkIE1hbmFnZXIgYXJlOlxuKlxuKiAgICogYGFjY291bnRgOiBUaGUgKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSBmb3IgdGhpcyBwcm9qZWN0LlxuKiAgICogYHByb2plY3RgOiBUaGUgKipQcm9qZWN0IElEKiogZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBncm91cGA6IFRoZSAqKkdyb3VwIE5hbWUqKiBmb3IgdGhpcyB3b3JsZC5cbiogICAqIGBydW5gOiBPcHRpb25zIHRvIHVzZSB3aGVuIGNyZWF0aW5nIG5ldyBydW5zIHdpdGggdGhlIG1hbmFnZXIsIGUuZy4gYHJ1bjogeyBmaWxlczogWydkYXRhLnhscyddIH1gLlxuKiAgICogYHJ1bi5tb2RlbGA6IFRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IG1vZGVsIGZpbGUgZm9yIHRoaXMgcHJvamVjdC4gUmVxdWlyZWQgaWYgeW91IGhhdmUgbm90IGFscmVhZHkgcGFzc2VkIGl0IGluIGFzIHBhcnQgb2YgdGhlIGBvcHRpb25zYCBwYXJhbWV0ZXIgZm9yIGFuIGVuY2xvc2luZyBjYWxsLlxuKlxuKiBGb3IgZXhhbXBsZTpcbipcbiogICAgICAgdmFyIHdNZ3IgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4qICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiogICAgICAgICAgcnVuOiB7IG1vZGVsOiAnc3VwcGx5LWNoYWluLnB5JyB9LFxuKiAgICAgICAgICBncm91cDogJ3RlYW0xJ1xuKiAgICAgICB9KTtcbipcbiogICAgICAgd01nci5nZXRDdXJyZW50UnVuKCk7XG4qL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBXb3JsZEFwaSA9IHJlcXVpcmUoJy4uL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbnZhciBSdW5NYW5hZ2VyID0gIHJlcXVpcmUoJy4vcnVuLW1hbmFnZXInKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG52YXIgd29ybGRBcGk7XG5cbi8vIHZhciBkZWZhdWx0cyA9IHtcbi8vICBhY2NvdW50OiAnJyxcbi8vICBwcm9qZWN0OiAnJyxcbi8vICBncm91cDogJycsXG4vLyAgdHJhbnNwb3J0OiB7XG4vLyAgfVxuLy8gfTtcblxuXG5mdW5jdGlvbiBidWlsZFN0cmF0ZWd5KHdvcmxkSWQsIGR0ZCkge1xuXG4gICAgcmV0dXJuIGZ1bmN0aW9uIEN0b3IocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xuXG4gICAgICAgICQuZXh0ZW5kKHRoaXMsIHtcbiAgICAgICAgICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdub3QgaW1wbGVtZW50ZC4gTmVlZCBhcGkgY2hhbmdlcycpO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgICAgICAgICAvL2dldCBvciBjcmVhdGUhXG4gICAgICAgICAgICAgICAgLy8gTW9kZWwgaXMgcmVxdWlyZWQgaW4gdGhlIG9wdGlvbnNcbiAgICAgICAgICAgICAgICB2YXIgbW9kZWwgPSB0aGlzLm9wdGlvbnMucnVuLm1vZGVsIHx8IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkSWQgfSlcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bklkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gX3RoaXMucnVuU2VydmljZS5sb2FkKHJ1bklkKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUuY2FsbCh0aGlzLCBydW4sIF90aGlzLnJ1blNlcnZpY2UpO1xuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAuZmFpbChkdGQucmVqZWN0KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfTtcbn1cblxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucyB8fCB7IHJ1bjoge30sIHdvcmxkOiB7fSB9O1xuXG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMucnVuKTtcbiAgICAkLmV4dGVuZCh0cnVlLCB0aGlzLm9wdGlvbnMsIHRoaXMub3B0aW9ucy53b3JsZCk7XG5cbiAgICB3b3JsZEFwaSA9IG5ldyBXb3JsZEFwaSh0aGlzLm9wdGlvbnMpO1xuICAgIHRoaXMuX2F1dGggPSBuZXcgQXV0aE1hbmFnZXIoKTtcbiAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgdmFyIGFwaSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHdvcmxkIChvYmplY3QpIGFuZCBhbiBpbnN0YW5jZSBvZiB0aGUgW1dvcmxkIEFQSSBBZGFwdGVyXSguLi93b3JsZC1hcGktYWRhcHRlci8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFdvcmxkKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQsIHdvcmxkQWRhcHRlcikge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd29ybGRBZGFwdGVyLmdldEN1cnJlbnRSdW5JZCgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB1c2VyIHdob3NlIHdvcmxkIGlzIGJlaW5nIGFjY2Vzc2VkLiBEZWZhdWx0cyB0byB0aGUgdXNlciBpbiB0aGUgY3VycmVudCBzZXNzaW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cCB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIGdyb3VwIGZvciB0aGUgdXNlciBpbiB0aGUgY3VycmVudCBzZXNzaW9uLlxuICAgICAgICAqL1xuICAgICAgICBnZXRDdXJyZW50V29ybGQ6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIGlmICghdXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWdyb3VwTmFtZSkge1xuICAgICAgICAgICAgICAgIGdyb3VwTmFtZSA9IHNlc3Npb24uZ3JvdXBOYW1lO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRXb3JsZEZvclVzZXIodXNlcklkLCBncm91cE5hbWUpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHVybnMgdGhlIGN1cnJlbnQgcnVuIChvYmplY3QpIGFuZCBhbiBpbnN0YW5jZSBvZiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgd01nci5nZXRDdXJyZW50UnVuKHttb2RlbDogJ215TW9kZWwucHknfSlcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuLCBydW5TZXJ2aWNlKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhydW4uaWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgcnVuU2VydmljZS5kbygnc3RhcnRHYW1lJyk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYG1vZGVsYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBtb2RlbCBmaWxlLiBSZXF1aXJlZCBpZiBub3QgYWxyZWFkeSBwYXNzZWQgaW4gYXMgYHJ1bi5tb2RlbGAgd2hlbiB0aGUgV29ybGQgTWFuYWdlciBpcyBjcmVhdGVkLlxuICAgICAgICAqL1xuICAgICAgICBnZXRDdXJyZW50UnVuOiBmdW5jdGlvbiAobW9kZWwpIHtcbiAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgdmFyIGN1ckdyb3VwTmFtZSA9IHNlc3Npb24uZ3JvdXBOYW1lO1xuXG4gICAgICAgICAgICBmdW5jdGlvbiBnZXRBbmRSZXN0b3JlTGF0ZXN0UnVuKHdvcmxkKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF3b3JsZCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCh7IGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IHBhcnQgb2YgYW55IHdvcmxkIScgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIGN1cnJlbnRXb3JsZElkID0gd29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgdmFyIHJ1bk9wdHMgPSAkLmV4dGVuZCh0cnVlLCBfdGhpcy5vcHRpb25zLCB7IG1vZGVsOiBtb2RlbCB9KTtcbiAgICAgICAgICAgICAgICB2YXIgc3RyYXRlZ3kgPSBidWlsZFN0cmF0ZWd5KGN1cnJlbnRXb3JsZElkLCBkdGQpO1xuICAgICAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSwge1xuICAgICAgICAgICAgICAgICAgICBzdHJhdGVneTogc3RyYXRlZ3ksXG4gICAgICAgICAgICAgICAgICAgIHJ1bjogcnVuT3B0c1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHZhciBybSA9IG5ldyBSdW5NYW5hZ2VyKG9wdCk7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gcm0uZ2V0UnVuKClcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUocnVuLCBybS5ydW5TZXJ2aWNlLCBybSk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLmdldEN1cnJlbnRXb3JsZChjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgICAgICAudGhlbihnZXRBbmRSZXN0b3JlTGF0ZXN0UnVuKTtcblxuICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgYXBpKTtcbn07XG4iLCIvKipcbiAqICMjRmlsZSBBUEkgU2VydmljZVxuICpcbiAqIFRoaXMgaXMgdXNlZCB0byB1cGxvYWQvZG93bmxvYWQgZmlsZXMgZGlyZWN0bHkgb250byBFcGljZW50ZXIsIGFuYWxvZ291cyB0byB1c2luZyB0aGUgRmlsZSBNYW5hZ2VyIFVJIGluIEVwaWNlbnRlciBkaXJlY3RseSBvciBTRlRQaW5nIGZpbGVzIGluLiBUaGUgQXNzZXQgQVBJIGlzIHR5cGljYWxseSB1c2VkIGZvciBhbGwgcHJvamVjdCB1c2UtY2FzZXMsIGFuZCBpdCdzIHVubGlrZWx5IHRoaXMgRmlsZSBTZXJ2aWNlIHdpbGwgYmUgdXNlZCBkaXJlY3RseSBleGNlcHQgYnkgQWRtaW4gdG9vbHMgKGUuZy4gRmxvdyBJbnNwZWN0b3IpLlxuICpcbiAqIFBhcnRpYWxseSBpbXBsZW1lbnRlZC5cbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgLy8gY29uZmlnIHx8IChjb25maWcgPSBjb25maWdTZXJ2aWNlLmdldCgpKTtcbiAgICB2YXIgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkoeyBzeW5jaHJvbm91czogdHJ1ZSB9KTtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8IHN0b3JlLmdldCgnZXBpY2VudGVyLnRva2VuJykgfHwgJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6ICcnLFxuXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG5cbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJylcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBhIGRpcmVjdG9yeSBsaXN0aW5nLCBvciBjb250ZW50cyBvZiBhIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZmlsZVBhdGhgICAgUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBmb2xkZXJUeXBlYCBPbmUgb2YgTW9kZWx8U3RhdGljfE5vZGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGdldENvbnRlbnRzOiBmdW5jdGlvbiAoZmlsZVBhdGgsIGZvbGRlclR5cGUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBwYXRoID0gZm9sZGVyVHlwZSArICcvJyArIGZpbGVQYXRoO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLCB7XG4gICAgICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZmlsZScpICsgcGF0aFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoJycsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG59O1xuIiwiLyoqXG4gKiAjI0Fzc2V0IEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIEFzc2V0IEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gc3RvcmUgYXNzZXRzIC0tIHJlc291cmNlcyBvciBmaWxlcyBvZiBhbnkga2luZCAtLSB1c2VkIGJ5IGEgcHJvamVjdCB3aXRoIGEgc2NvcGUgdGhhdCBpcyBzcGVjaWZpYyB0byBwcm9qZWN0LCBncm91cCwgb3IgZW5kIHVzZXIuXG4gKlxuICogQXNzZXRzIGFyZSB1c2VkIHdpdGggW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL3Byb2plY3RfYWRtaW4vI3RlYW0pLiBPbmUgY29tbW9uIHVzZSBjYXNlIGlzIGhhdmluZyBlbmQgdXNlcnMgaW4gYSBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpIG9yIGluIGEgW211bHRpcGxheWVyIHdvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpIHVwbG9hZCBkYXRhIC0tIHZpZGVvcyBjcmVhdGVkIGR1cmluZyBnYW1lIHBsYXksIHByb2ZpbGUgcGljdHVyZXMgZm9yIGN1c3RvbWl6aW5nIHRoZWlyIGV4cGVyaWVuY2UsIGV0Yy4gLS0gYXMgcGFydCBvZiBwbGF5aW5nIHRocm91Z2ggdGhlIHByb2plY3QuXG4gKlxuICogUmVzb3VyY2VzIGNyZWF0ZWQgdXNpbmcgdGhlIEFzc2V0IEFkYXB0ZXIgYXJlIHNjb3BlZDpcbiAqXG4gKiAgKiBQcm9qZWN0IGFzc2V0cyBhcmUgd3JpdGFibGUgb25seSBieSBbdGVhbSBtZW1iZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSksIHRoYXQgaXMsIEVwaWNlbnRlciBhdXRob3JzLlxuICogICogR3JvdXAgYXNzZXRzIGFyZSB3cml0YWJsZSBieSBhbnlvbmUgd2l0aCBhY2Nlc3MgdG8gdGhlIHByb2plY3QgdGhhdCBpcyBwYXJ0IG9mIHRoYXQgcGFydGljdWxhciBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLiBUaGlzIGluY2x1ZGVzIGFsbCBbdGVhbSBtZW1iZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSkgKEVwaWNlbnRlciBhdXRob3JzKSBhbmQgYW55IFtlbmQgdXNlcnNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2Vycykgd2hvIGFyZSBtZW1iZXJzIG9mIHRoZSBncm91cCAtLSBib3RoIGZhY2lsaXRhdG9ycyBhbmQgc3RhbmRhcmQgZW5kIHVzZXJzLlxuICogICogVXNlciBhc3NldHMgYXJlIHdyaXRhYmxlIGJ5IHRoZSBzcGVjaWZpYyBlbmQgdXNlciwgYW5kIGJ5IHRoZSBmYWNpbGl0YXRvciBvZiB0aGUgZ3JvdXAuXG4gKiAgKiBBbGwgYXNzZXRzIGFyZSByZWFkYWJsZSBieSBhbnlvbmUgd2l0aCB0aGUgZXhhY3QgVVJJLlxuICpcbiAqIFRvIHVzZSB0aGUgQXNzZXQgQWRhcHRlciwgaW5zdGFudGlhdGUgaXQgYW5kIHRoZW4gYWNjZXNzIHRoZSBtZXRob2RzIHByb3ZpZGVkLiBJbnN0YW50aWF0aW5nIHJlcXVpcmVzIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBpbiB0aGUgRXBpY2VudGVyIHVzZXIgaW50ZXJmYWNlKSBhbmQgcHJvamVjdCBpZCAoKipQcm9qZWN0IElEKiopLiBUaGUgZ3JvdXAgbmFtZSBpcyByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSBncm91cCBzY29wZSwgYW5kIHRoZSBncm91cCBuYW1lIGFuZCB1c2VySWQgYXJlIHJlcXVpcmVkIGZvciBhc3NldHMgd2l0aCBhIHVzZXIgc2NvcGUuIElmIG5vdCBpbmNsdWRlZCwgdGhleSBhcmUgdGFrZW4gZnJvbSB0aGUgbG9nZ2VkIGluIHVzZXIncyBzZXNzaW9uIGluZm9ybWF0aW9uIGlmIG5lZWRlZC5cbiAqXG4gKiBXaGVuIGNyZWF0aW5nIGFuIGFzc2V0LCB5b3UgY2FuIHBhc3MgaW4gdGV4dCAoZW5jb2RlZCBkYXRhKSB0byB0aGUgYGNyZWF0ZSgpYCBjYWxsLiBBbHRlcm5hdGl2ZWx5LCB5b3UgY2FuIG1ha2UgdGhlIGBjcmVhdGUoKWAgY2FsbCBhcyBwYXJ0IG9mIGFuIEhUTUwgZm9ybSBhbmQgcGFzcyBpbiBhIGZpbGUgdXBsb2FkZWQgdmlhIHRoZSBmb3JtLlxuICpcbiAqICAgICAgIC8vIGluc3RhbnRpYXRlIHRoZSBBc3NldCBBZGFwdGVyXG4gKiAgICAgICB2YXIgYWEgPSBuZXcgRi5zZXJ2aWNlLkFzc2V0KHtcbiAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAqICAgICAgICAgIHVzZXJJZDogJzEyMzQ1J1xuICogICAgICAgfSk7XG4gKlxuICogICAgICAgLy8gY3JlYXRlIGEgbmV3IGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICogICAgICAgYWEuY3JlYXRlKCd0ZXN0LnR4dCcsIHtcbiAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSFJsYzNRZ1ptbHNaUzQ9JyxcbiAqICAgICAgICAgICBjb250ZW50VHlwZTogJ3RleHQvcGxhaW4nXG4gKiAgICAgICB9LCB7IHNjb3BlOiAndXNlcicgfSk7XG4gKlxuICogICAgICAgLy8gYWx0ZXJuYXRpdmVseSwgY3JlYXRlIGEgbmV3IGFzc2V0IHVzaW5nIGEgZmlsZSB1cGxvYWRlZCB0aHJvdWdoIGEgZm9ybVxuICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICogICAgICAgLy9cbiAqICAgICAgIC8vIDxmb3JtIGlkPVwidXBsb2FkLWZpbGVcIj5cbiAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAqICAgICAgIC8vICAgPGJ1dHRvbiB0eXBlPVwic3VibWl0XCI+VXBsb2FkIG15RmlsZTwvYnV0dG9uPlxuICogICAgICAgLy8gPC9mb3JtPlxuICogICAgICAgLy9cbiAqICAgICAgICQoJyN1cGxvYWQtZmlsZScpLm9uKCdzdWJtaXQnLCBmdW5jdGlvbiAoZSkge1xuICogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI2ZpbGVuYW1lJykudmFsKCk7XG4gKiAgICAgICAgICB2YXIgZGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gKiAgICAgICAgICBkYXRhLmFwcGVuZCgnZmlsZScsIGlucHV0Q29udHJvbC5maWxlc1swXSwgZmlsZW5hbWUpO1xuICpcbiAqICAgICAgICAgIGFhLmNyZWF0ZShmaWxlbmFtZSwgZGF0YSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICogICAgICAgfSk7XG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xuLy8gdmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9tYW5hZ2Vycy9rZXktbmFtZXMnKTtcblxudmFyIGFwaUVuZHBvaW50ID0gJ2Fzc2V0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG4gICAgdmFyIHNlc3Npb24gPSBKU09OLnBhcnNlKHN0b3JlLmdldChrZXlOYW1lcy5FUElfU0VTU0lPTl9LRVkpIHx8ICd7fScpO1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiBzdG9yZS5nZXQoa2V5TmFtZXMuRVBJX0NPT0tJRV9LRVkpIHx8ICcnLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBncm91cCBuYW1lLiBEZWZhdWx0cyB0byBzZXNzaW9uJ3MgYGdyb3VwTmFtZWAuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBncm91cDogc2Vzc2lvbi5ncm91cE5hbWUsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgdXNlciBpZC4gRGVmYXVsdHMgdG8gc2Vzc2lvbidzIGB1c2VySWRgLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdXNlcklkOiBzZXNzaW9uLnVzZXJJZCxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBzY29wZSBmb3IgdGhlIGFzc2V0LiBWYWxpZCB2YWx1ZXMgYXJlOiBgdXNlcmAsIGBncm91cGAsIGFuZCBgcHJvamVjdGAuIFNlZSBhYm92ZSBmb3IgdGhlIHJlcXVpcmVkIHBlcm1pc3Npb25zIHRvIHdyaXRlIHRvIGVhY2ggc2NvcGUuIERlZmF1bHRzIHRvIGB1c2VyYCwgbWVhbmluZyB0aGUgY3VycmVudCBlbmQgdXNlciBvciBhIGZhY2lsaXRhdG9yIGluIHRoZSBlbmQgdXNlcidzIGdyb3VwIGNhbiBlZGl0IHRoZSBhc3NldC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHNjb3BlOiAndXNlcicsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBEZXRlcm1pbmVzIGlmIGEgcmVxdWVzdCB0byBsaXN0IHRoZSBhc3NldHMgaW4gYSBzY29wZSBpbmNsdWRlcyB0aGUgY29tcGxldGUgVVJMIGZvciBlYWNoIGFzc2V0IChgdHJ1ZWApLCBvciBvbmx5IHRoZSBmaWxlIG5hbWVzIG9mIHRoZSBhc3NldHMgKGBmYWxzZWApLiBEZWZhdWx0cyB0byBgdHJ1ZWAuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgZnVsbFVybDogdHJ1ZSxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSB0cmFuc3BvcnQgb2JqZWN0IGNvbnRhaW5zIHRoZSBvcHRpb25zIHBhc3NlZCB0byB0aGUgWEhSIHJlcXVlc3QuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHtcbiAgICAgICAgICAgIHByb2Nlc3NEYXRhOiBmYWxzZVxuICAgICAgICB9XG4gICAgfTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmFjY291bnQgPSB1cmxDb25maWcuYWNjb3VudFBhdGg7XG4gICAgfVxuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgYXNzZXRBcGlQYXJhbXMgPSBbJ2VuY29kaW5nJywgJ2RhdGEnLCAnY29udGVudFR5cGUnXTtcbiAgICB2YXIgc2NvcGVDb25maWcgPSB7XG4gICAgICAgIHVzZXI6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddLFxuICAgICAgICBncm91cDogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSxcbiAgICAgICAgcHJvamVjdDogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnXSxcbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlRmlsZW5hbWUgPSBmdW5jdGlvbiAoZmlsZW5hbWUpIHtcbiAgICAgICAgaWYgKCFmaWxlbmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdmaWxlbmFtZSBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlVXJsUGFyYW1zID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHBhcnRLZXlzID0gc2NvcGVDb25maWdbb3B0aW9ucy5zY29wZV07XG4gICAgICAgIGlmICghcGFydEtleXMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignc2NvcGUgcGFyYW1ldGVyIGlzIG5lZWRlZC4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgICQuZWFjaChwYXJ0S2V5cywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKCFvcHRpb25zW3RoaXNdKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMgKyAnIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICB2YXIgYnVpbGRVcmwgPSBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVVcmxQYXJhbXMob3B0aW9ucyk7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICB2YXIgcGFydHMgPSAkLm1hcChwYXJ0S2V5cywgZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbnNba2V5XTtcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChmaWxlbmFtZSkge1xuICAgICAgICAgICAgLy8gVGhpcyBwcmV2ZW50cyBhZGRpbmcgYSB0cmFpbGluZyAvIGluIHRoZSBVUkwgYXMgdGhlIEFzc2V0IEFQSVxuICAgICAgICAgICAgLy8gZG9lcyBub3Qgd29yayBjb3JyZWN0bHkgd2l0aCBpdFxuICAgICAgICAgICAgZmlsZW5hbWUgPSAnLycgKyBmaWxlbmFtZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcGFydHMuam9pbignLycpICsgZmlsZW5hbWU7XG4gICAgfTtcblxuICAgIC8vIFByaXZhdGUgZnVuY3Rpb24sIGFsbCByZXF1ZXN0cyBmb2xsb3cgYSBtb3JlIG9yIGxlc3Mgc2FtZSBhcHByb2FjaCB0b1xuICAgIC8vIHVzZSB0aGUgQXNzZXQgQVBJIGFuZCB0aGUgZGlmZmVyZW5jZSBpcyB0aGUgSFRUUCB2ZXJiXG4gICAgLy9cbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gYG1ldGhvZGAgKFJlcXVpcmVkKSBIVFRQIHZlcmJcbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlL3JlcGxhY2UvY3JlYXRlXG4gICAgLy8gQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICB2YXIgdXBsb2FkID0gZnVuY3Rpb24gKG1ldGhvZCwgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YWxpZGF0ZUZpbGVuYW1lKGZpbGVuYW1lKTtcbiAgICAgICAgLy8gbWFrZSBzdXJlIHRoZSBwYXJhbWV0ZXIgaXMgY2xlYW5cbiAgICAgICAgbWV0aG9kID0gbWV0aG9kLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBjb250ZW50VHlwZSA9IHBhcmFtcyBpbnN0YW5jZW9mIEZvcm1EYXRhID09PSB0cnVlID8gZmFsc2UgOiAnYXBwbGljYXRpb24vanNvbic7XG4gICAgICAgIGlmIChjb250ZW50VHlwZSA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nKSB7XG4gICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgYXNzZXRBcGlQYXJhbXMpO1xuICAgICAgICB9IGVsc2UgeyAvLyBlbHNlIHdlJ3JlIHNlbmRpbmcgZm9ybSBkYXRhIHdoaWNoIGdvZXMgZGlyZWN0bHkgaW4gcmVxdWVzdCBib2R5XG4gICAgICAgICAgICAvLyBGb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSB1cGxvYWRzIHRoZSBmaWxlbmFtZSBpcyBub3Qgc2V0IGluIHRoZSBVUkwsXG4gICAgICAgICAgICAvLyBpdCdzIGdldHRpbmcgcGlja2VkIGJ5IHRoZSBGb3JtRGF0YSBmaWVsZCBmaWxlbmFtZS5cbiAgICAgICAgICAgIGZpbGVuYW1lID0gbWV0aG9kID09PSAncG9zdCcgfHwgbWV0aG9kID09PSAncHV0JyA/ICcnIDogZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsLCBjb250ZW50VHlwZTogY29udGVudFR5cGUgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHBbbWV0aG9kXShwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgKiBDcmVhdGVzIGEgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLiBUaGUgc2VydmVyIHJldHVybnMgYW4gZXJyb3IgKHN0YXR1cyBjb2RlIGA0MDlgLCBjb25mbGljdCkgaWYgdGhlIGZpbGUgYWxyZWFkeSBleGlzdHMsIHNvXG4gICAgICAgICogY2hlY2sgZmlyc3Qgd2l0aCBhIGBsaXN0KClgIG9yIGEgYGdldCgpYC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gICAgICAgICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICAgICogICAgICAgICAgdXNlcklkOiAnJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gY3JlYXRlIGEgbmV3IGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSFJsYzNRZ1ptbHNaUzQ9JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlXCIgdHlwZT1cImZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAgICAgICAgKiAgICAgICAvLyA8L2Zvcm0+XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI2ZpbGVuYW1lJykudmFsKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgaW5wdXRDb250cm9sID0gJCgnI2ZpbGUnKVswXTtcbiAgICAgICAgKiAgICAgICAgICBkYXRhLmFwcGVuZCgnZmlsZScsIGlucHV0Q29udHJvbC5maWxlc1swXSwgZmlsZW5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgYWEuY3JlYXRlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byBjcmVhdGUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncG9zdCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSSwgZmV0Y2hpbmcgdGhlIGFzc2V0IGNvbnRlbnQuIChUbyBnZXQgYSBsaXN0XG4gICAgICAgICogb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLCB1c2UgYGxpc3QoKWAuKVxuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIHJldHJpZXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGdldFNlcnZpY2VPcHRpb25zID0gX3BpY2soc2VydmljZU9wdGlvbnMsIFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddKTtcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIGdldFNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybChmaWxlbmFtZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGxpc3Qgb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmxpc3QoeyBmdWxsVXJsOiB0cnVlIH0pLnRoZW4oZnVuY3Rpb24oZmlsZUxpc3Qpe1xuICAgICAgICAqICAgICAgICAgICBjb25zb2xlLmxvZygnYXJyYXkgb2YgZmlsZXMgPSAnLCBmaWxlTGlzdCk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnNjb3BlYCAoT3B0aW9uYWwpIFRoZSBzY29wZSAoYHVzZXJgLCBgZ3JvdXBgLCBgcHJvamVjdGApLlxuICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gYG9wdGlvbnMuZnVsbFVybGAgKE9wdGlvbmFsKSBEZXRlcm1pbmVzIGlmIHRoZSBsaXN0IG9mIGFzc2V0cyBpbiBhIHNjb3BlIGluY2x1ZGVzIHRoZSBjb21wbGV0ZSBVUkwgZm9yIGVhY2ggYXNzZXQgKGB0cnVlYCksIG9yIG9ubHkgdGhlIGZpbGUgbmFtZXMgb2YgdGhlIGFzc2V0cyAoYGZhbHNlYCkuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgbGlzdDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKCcnLCB1cmxPcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHVybE9wdGlvbnMsIHsgdXJsOiB1cmwgfSk7XG4gICAgICAgICAgICB2YXIgZnVsbFVybCA9IGdldE9wdGlvbnMuZnVsbFVybDtcblxuICAgICAgICAgICAgaWYgKCFmdWxsVXJsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBmdWxsUGF0aEZpbGVzID0gJC5tYXAoZmlsZXMsIGZ1bmN0aW9uIChmaWxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShmdWxsUGF0aEZpbGVzLCBtZSk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChkdGQucmVqZWN0KTtcblxuICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGFjZXMgYW4gZXhpc3RpbmcgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgZW5jb2RlZCB0ZXh0XG4gICAgICAgICogICAgICAgYWEucmVwbGFjZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSE5sWTI5dVpDQjBaWE4wSUdacGJHVXUnLFxuICAgICAgICAqICAgICAgICAgICBjb250ZW50VHlwZTogJ3RleHQvcGxhaW4nXG4gICAgICAgICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gYWx0ZXJuYXRpdmVseSwgcmVwbGFjZSBhbiBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInJlcGxhY2UtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJyZXBsYWNlLWZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlJlcGxhY2UgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3JlcGxhY2UtZmlsZScpLm9uKCdzdWJtaXQnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZmlsZW5hbWUgPSAkKCcjcmVwbGFjZS1maWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLnJlcGxhY2UoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSBiZWluZyByZXBsYWNlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgKE9wdGlvbmFsKSBCb2R5IHBhcmFtZXRlcnMgdG8gc2VuZCB0byB0aGUgQXNzZXQgQVBJLiBSZXF1aXJlZCBpZiB0aGUgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAsIG90aGVyd2lzZSBpZ25vcmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmVuY29kaW5nYCBFaXRoZXIgYEhFWGAgb3IgYEJBU0VfNjRgLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5kYXRhYCBUaGUgZW5jb2RlZCBkYXRhIGZvciB0aGUgZmlsZS4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuY29udGVudFR5cGVgIFRoZSBtaW1lIHR5cGUgb2YgdGhlIGZpbGUuIE9wdGlvbmFsLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICByZXBsYWNlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncHV0JywgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogRGVsZXRlcyBhIGZpbGUgZnJvbSB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmRlbGV0ZShzYW1wbGVGaWxlTmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGU6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgnZGVsZXRlJywgZmlsZW5hbWUsIHt9LCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhc3NldFVybDogZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICpcbiAqICMjQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2UgcHJvdmlkZXMgbWV0aG9kcyBmb3IgbG9nZ2luZyBpbiBhbmQgbG9nZ2luZyBvdXQuIE9uIGxvZ2luLCB0aGlzIHNlcnZpY2UgY3JlYXRlcyBhbmQgcmV0dXJucyBhIHVzZXIgYWNjZXNzIHRva2VuLlxuICpcbiAqIFVzZXIgYWNjZXNzIHRva2VucyBhcmUgcmVxdWlyZWQgZm9yIGVhY2ggY2FsbCB0byBFcGljZW50ZXIuIChTZWUgW1Byb2plY3QgQWNjZXNzXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pIGZvciBtb3JlIGluZm9ybWF0aW9uLilcbiAqXG4gKiBJZiB5b3UgbmVlZCBhZGRpdGlvbmFsIGZ1bmN0aW9uYWxpdHkgLS0gc3VjaCBhcyB0cmFja2luZyBzZXNzaW9uIGluZm9ybWF0aW9uLCBlYXNpbHkgcmV0cmlldmluZyB0aGUgdXNlciB0b2tlbiwgb3IgZ2V0dGluZyB0aGUgZ3JvdXBzIHRvIHdoaWNoIGFuIGVuZCB1c2VyIGJlbG9uZ3MgLS0gY29uc2lkZXIgdXNpbmcgdGhlIFtBdXRob3JpemF0aW9uIE1hbmFnZXJdKC4uL2F1dGgtbWFuYWdlci8pIGluc3RlYWQuXG4gKlxuICogICAgICB2YXIgYXV0aCA9IG5ldyBGLnNlcnZpY2UuQXV0aCgpO1xuICogICAgICBhdXRoLmxvZ2luKHsgdXNlck5hbWU6ICdqc21pdGhAYWNtZXNpbXVsYXRpb25zLmNvbScsXG4gKiAgICAgICAgICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnIH0pO1xuICogICAgICBhdXRoLmxvZ291dCgpO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJOYW1lOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwYXNzd29yZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBSZXF1aXJlZCBpZiB0aGUgYHVzZXJOYW1lYCBpcyBmb3IgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2F1dGhlbnRpY2F0aW9uJylcbiAgICB9KTtcbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9ncyB1c2VyIGluLCByZXR1cm5pbmcgdGhlIHVzZXIgYWNjZXNzIHRva2VuLlxuICAgICAgICAgKlxuICAgICAgICAgKiBJZiBubyBgdXNlck5hbWVgIG9yIGBwYXNzd29yZGAgd2VyZSBwcm92aWRlZCBpbiB0aGUgaW5pdGlhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMsIHRoZXkgYXJlIHJlcXVpcmVkIGluIHRoZSBgb3B0aW9uc2AgaGVyZS4gSWYgbm8gYGFjY291bnRgIHdhcyBwcm92aWRlZCBpbiB0aGUgaW5pdGlhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMgYW5kIHRoZSBgdXNlck5hbWVgIGlzIGZvciBhbiBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycyksIHRoZSBgYWNjb3VudGAgaXMgcmVxdWlyZWQgYXMgd2VsbC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBhdXRoLmxvZ2luKHtcbiAgICAgICAgICogICAgICAgICAgdXNlck5hbWU6ICdqc21pdGgnLFxuICAgICAgICAgKiAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyxcbiAgICAgICAgICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnIH0pXG4gICAgICAgICAqICAgICAgLnRoZW4oZnVuY3Rpb24gKHRva2VuKSB7XG4gICAgICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKFwidXNlciBhY2Nlc3MgdG9rZW4gaXM6IFwiLCB0b2tlbi5hY2Nlc3NfdG9rZW4pO1xuICAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2dpbjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHsgc3VjY2VzczogJC5ub29wIH0sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGlmICghaHR0cE9wdGlvbnMudXNlck5hbWUgfHwgIWh0dHBPcHRpb25zLnBhc3N3b3JkKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlc3AgPSB7IHN0YXR1czogNDAxLCBzdGF0dXNNZXNzYWdlOiAnTm8gdXNlcm5hbWUgb3IgcGFzc3dvcmQgc3BlY2lmaWVkLicgfTtcbiAgICAgICAgICAgICAgICBpZiAob3B0aW9ucy5lcnJvcikge1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmVycm9yLmNhbGwodGhpcywgcmVzcCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuICQuRGVmZXJyZWQoKS5yZWplY3QocmVzcCkucHJvbWlzZSgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcG9zdFBhcmFtcyA9IHtcbiAgICAgICAgICAgICAgICB1c2VyTmFtZTogaHR0cE9wdGlvbnMudXNlck5hbWUsXG4gICAgICAgICAgICAgICAgcGFzc3dvcmQ6IGh0dHBPcHRpb25zLnBhc3N3b3JkLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmIChodHRwT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgICAgICAgICAgLy9wYXNzIGluIG51bGwgZm9yIGFjY291bnQgdW5kZXIgb3B0aW9ucyBpZiB5b3UgZG9uJ3Qgd2FudCBpdCB0byBiZSBzZW50XG4gICAgICAgICAgICAgICAgcG9zdFBhcmFtcy5hY2NvdW50ID0gaHR0cE9wdGlvbnMuYWNjb3VudDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwb3N0UGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvZ3MgdXNlciBvdXQgZnJvbSBzcGVjaWZpZWQgYWNjb3VudHMuXG4gICAgICAgICAqIEVwaWNlbnRlciBsb2dvdXQgaXMgbm90IGltcGxlbWVudGVkIHlldCwgYWRkZWQgYSBkdW1teSBwcm9taXNlIHRoYXQgZ2V0cyBhdXRvbWF0aWNhbGx5IHJlc29sdmVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGF1dGgubG9nb3V0KCk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvZ291dDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBTZXJ2aWNlXG4gKlxuICogVGhlIEVwaWNlbnRlciBwbGF0Zm9ybSBwcm92aWRlcyBhIHB1c2ggY2hhbm5lbCwgd2hpY2ggYWxsb3dzIHlvdSB0byBwdWJsaXNoIGFuZCBzdWJzY3JpYmUgdG8gbWVzc2FnZXMgd2l0aGluIGEgW3Byb2plY3RdKC4uLy4uLy4uL2dsb3NzYXJ5LyNwcm9qZWN0cyksIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcyksIG9yIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS4gVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIENoYW5uZWwgU2VydmljZSBpcyBhIGJ1aWxkaW5nIGJsb2NrIGZvciB0aGlzIGZ1bmN0aW9uYWxpdHkuIEl0IGNyZWF0ZXMgYSBwdWJsaXNoLXN1YnNjcmliZSBvYmplY3QsIGFsbG93aW5nIHlvdSB0byBwdWJsaXNoIG1lc3NhZ2VzLCBzdWJzY3JpYmUgdG8gbWVzc2FnZXMsIG9yIHVuc3Vic2NyaWJlIGZyb20gbWVzc2FnZXMgZm9yIGEgZ2l2ZW4gJ3RvcGljJyBvbiBhIGAkLmNvbWV0ZGAgdHJhbnNwb3J0IGluc3RhbmNlLlxuICpcbiAqIFR5cGljYWxseSwgeW91IHVzZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSB0byBjcmVhdGUgb3IgcmV0cmlldmUgY2hhbm5lbHMsIHRoZW4gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UgYHN1YnNjcmliZSgpYCBhbmQgYHB1Ymxpc2goKWAgbWV0aG9kcyB0byBsaXN0ZW4gdG8gb3IgdXBkYXRlIGRhdGEuIChGb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIEVwaWNlbnRlcidzIHB1c2ggY2hhbm5lbCwgc2VlIHRoZSBpbnRyb2R1Y3Rvcnkgbm90ZXMgb24gdGhlIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIHBhZ2UuKVxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgU2VydmljZS4gU2VlIFtJbmNsdWRpbmcgRXBpY2VudGVyLmpzXSguLi8uLi8jaW5jbHVkZSkuXG4gKlxuICogVG8gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UsIGluc3RhbnRpYXRlIGl0LCB0aGVuIG1ha2UgY2FsbHMgdG8gYW55IG9mIHRoZSBtZXRob2RzIHlvdSBuZWVkLlxuICpcbiAqICAgICAgICB2YXIgY3MgPSBuZXcgRi5zZXJ2aWNlLkNoYW5uZWwoKTtcbiAqICAgICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcycsIHsgcHJpY2U6IDUwIH0pO1xuICpcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciBpbnN0YW50aWF0aW5nIGEgQ2hhbm5lbCBTZXJ2aWNlIGluY2x1ZGU6XG4gKlxuICogKiBgb3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLlxuICogKiBgb3B0aW9ucy5iYXNlYCBUaGUgYmFzZSB0b3BpYy4gVGhpcyBpcyBhZGRlZCBhcyBhIHByZWZpeCB0byBhbGwgZnVydGhlciB0b3BpY3MgeW91IHB1Ymxpc2ggb3Igc3Vic2NyaWJlIHRvIHdoaWxlIHdvcmtpbmcgd2l0aCB0aGlzIENoYW5uZWwgU2VydmljZS5cbiAqICogYG9wdGlvbnMudG9waWNSZXNvbHZlcmAgQSBmdW5jdGlvbiB0aGF0IHByb2Nlc3NlcyBhbGwgJ3RvcGljcycgcGFzc2VkIGludG8gdGhlIGBwdWJsaXNoYCBhbmQgYHN1YnNjcmliZWAgbWV0aG9kcy4gVGhpcyBpcyB1c2VmdWwgaWYgeW91IHdhbnQgdG8gaW1wbGVtZW50IHlvdXIgb3duIHNlcmlhbGl6ZSBmdW5jdGlvbnMgZm9yIGNvbnZlcnRpbmcgY3VzdG9tIG9iamVjdHMgdG8gdG9waWMgbmFtZXMuIFJldHVybnMgYSBTdHJpbmcuIEJ5IGRlZmF1bHQsIGl0IGp1c3QgZWNob2VzIHRoZSB0b3BpYy5cbiAqICogYG9wdGlvbnMudHJhbnNwb3J0YCBUaGUgaW5zdGFuY2Ugb2YgYCQuY29tZXRkYCB0byBob29rIG9udG8uIFNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZCBvbiBjb21ldGQuXG4gKi9cbnZhciBDaGFubmVsID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBiYXNlIHRvcGljLiBUaGlzIGlzIGFkZGVkIGFzIGEgcHJlZml4IHRvIGFsbCBmdXJ0aGVyIHRvcGljcyB5b3UgcHVibGlzaCBvciBzdWJzY3JpYmUgdG8gd2hpbGUgd29ya2luZyB3aXRoIHRoaXMgQ2hhbm5lbCBTZXJ2aWNlLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYmFzZTogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEEgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgYWxsICd0b3BpY3MnIHBhc3NlZCBpbnRvIHRoZSBgcHVibGlzaGAgYW5kIGBzdWJzY3JpYmVgIG1ldGhvZHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGltcGxlbWVudCB5b3VyIG93biBzZXJpYWxpemUgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGN1c3RvbSBvYmplY3RzIHRvIHRvcGljIG5hbWVzLiBCeSBkZWZhdWx0LCBpdCBqdXN0IGVjaG9lcyB0aGUgdG9waWMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICogYHRvcGljYCBUb3BpYyB0byBwYXJzZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqICpTdHJpbmcqOiBUaGlzIGZ1bmN0aW9uIHNob3VsZCByZXR1cm4gYSBzdHJpbmcgdG9waWMuXG4gICAgICAgICAqXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHRvcGljUmVzb2x2ZXI6IGZ1bmN0aW9uICh0b3BpYykge1xuICAgICAgICAgICAgcmV0dXJuIHRvcGljO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgaW5zdGFuY2Ugb2YgYCQuY29tZXRkYCB0byBob29rIG9udG8uXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IG51bGxcbiAgICB9O1xuICAgIHRoaXMuY2hhbm5lbE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xufTtcblxudmFyIG1ha2VOYW1lID0gZnVuY3Rpb24gKGNoYW5uZWxOYW1lLCB0b3BpYykge1xuICAgIC8vUmVwbGFjZSB0cmFpbGluZy9kb3VibGUgc2xhc2hlc1xuICAgIHZhciBuZXdOYW1lID0gKGNoYW5uZWxOYW1lID8gKGNoYW5uZWxOYW1lICsgJy8nICsgdG9waWMpIDogdG9waWMpLnJlcGxhY2UoL1xcL1xcLy9nLCAnLycpLnJlcGxhY2UoL1xcLyQvLCcnKTtcbiAgICByZXR1cm4gbmV3TmFtZTtcbn07XG5cblxuQ2hhbm5lbC5wcm90b3R5cGUgPSAkLmV4dGVuZChDaGFubmVsLnByb3RvdHlwZSwge1xuXG4gICAgLy8gZnV0dXJlIGZ1bmN0aW9uYWxpdHk6XG4gICAgLy8gICAgICAvLyBTZXQgdGhlIGNvbnRleHQgZm9yIHRoZSBjYWxsYmFja1xuICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4nLCBmdW5jdGlvbiAoKSB7IHRoaXMuaW5uZXJIVE1MID0gJ1RyaWdnZXJlZCd9LCBkb2N1bWVudC5ib2R5KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBDb250cm9sIHRoZSBvcmRlciBvZiBvcGVyYXRpb25zIGJ5IHNldHRpbmcgdGhlIGBwcmlvcml0eWBcbiAgICAgLy8gICAgICBjcy5zdWJzY3JpYmUoJ3J1bicsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDl9KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBPbmx5IGV4ZWN1dGUgdGhlIGNhbGxiYWNrLCBgY2JgLCBpZiB0aGUgdmFsdWUgb2YgdGhlIGBwcmljZWAgdmFyaWFibGUgaXMgNTBcbiAgICAgLy8gICAgICBjcy5zdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6IDUwfSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIGdyZWF0ZXIgdGhhbiA1MFxuICAgICAvLyAgICAgIHN1YnNjcmliZSgncnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDMwLCB2YWx1ZTogJz41MCd9KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBPbmx5IGV4ZWN1dGUgdGhlIGNhbGxiYWNrLCBgY2JgLCBpZiB0aGUgdmFsdWUgb2YgdGhlIGBwcmljZWAgdmFyaWFibGUgaXMgZXZlblxuICAgICAvLyAgICAgIHN1YnNjcmliZSgncnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDMwLCB2YWx1ZTogZnVuY3Rpb24gKHZhbCkge3JldHVybiB2YWwgJSAyID09PSAwfX0pO1xuXG5cbiAgICAvKipcbiAgICAgKiBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBhIHRvcGljLlxuICAgICAqXG4gICAgICogVGhlIHRvcGljIHNob3VsZCBpbmNsdWRlIHRoZSBmdWxsIHBhdGggb2YgdGhlIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzKSwgcHJvamVjdCBpZCwgYW5kIGdyb3VwIG5hbWUuIChJbiBtb3N0IGNhc2VzLCBpdCBpcyBzaW1wbGVyIHRvIHVzZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSBpbnN0ZWFkLCBpbiB3aGljaCBjYXNlIHRoaXMgaXMgY29uZmlndXJlZCBmb3IgeW91LilcbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGVzKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIGNiID0gZnVuY3Rpb24odmFsKSB7IGNvbnNvbGUubG9nKHZhbC5kYXRhKTsgfTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSB0b3AtbGV2ZWwgJ3J1bicgdG9waWNcbiAgICAgKiAgICAgIGNzLnN1YnNjcmliZSgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gY2hpbGRyZW4gb2YgdGhlICdydW4nIHRvcGljLiBOb3RlIHRoaXMgd2lsbCBhbHNvIGJlIHRyaWdnZXJlZCBmb3IgY2hhbmdlcyB0byBydW4ueC55LnouXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vKicsIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYm90aCB0aGUgdG9wLWxldmVsICdydW4nIHRvcGljIGFuZCBpdHMgY2hpbGRyZW5cbiAgICAgKiAgICAgIGNzLnN1YnNjcmliZShbJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLFxuICAgICAqICAgICAgICAgICcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuLyonXSwgY2IpO1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBhIHBhcnRpY3VsYXIgdmFyaWFibGVcbiAgICAgKiAgICAgIHN1YnNjcmliZSgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYik7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKlN0cmluZyogUmV0dXJucyBhIHRva2VuIHlvdSBjYW4gbGF0ZXIgdXNlIHRvIHVuc3Vic2NyaWJlLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8QXJyYXl9ICAgYHRvcGljYCAgICBMaXN0IG9mIHRvcGljcyB0byBsaXN0ZW4gZm9yIGNoYW5nZXMgb24uXG4gICAgICogQHBhcmFtICB7RnVuY3Rpb259IGBjYWxsYmFja2AgQ2FsbGJhY2sgZnVuY3Rpb24gdG8gZXhlY3V0ZS4gQ2FsbGJhY2sgaXMgY2FsbGVkIHdpdGggc2lnbmF0dXJlIGAoZXZ0LCBwYXlsb2FkLCBtZXRhZGF0YSlgLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gICBgY29udGV4dGAgIENvbnRleHQgaW4gd2hpY2ggdGhlIGBjYWxsYmFja2AgaXMgZXhlY3V0ZWQuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSAgIGBvcHRpb25zYCAgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKiBAcGFyYW0gIHtOdW1iZXJ9ICAgYG9wdGlvbnMucHJpb3JpdHlgICBVc2VkIHRvIGNvbnRyb2wgb3JkZXIgb2Ygb3BlcmF0aW9ucy4gRGVmYXVsdHMgdG8gMC4gQ2FuIGJlIGFueSArdmUgb3IgLXZlIG51bWJlci5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8TnVtYmVyfEZ1bmN0aW9ufSAgIGBvcHRpb25zLnZhbHVlYCBUaGUgYGNhbGxiYWNrYCBpcyBvbmx5IHRyaWdnZXJlZCBpZiB0aGlzIGNvbmRpdGlvbiBtYXRjaGVzLiBTZWUgZXhhbXBsZXMgZm9yIGRldGFpbHMuXG4gICAgICpcbiAgICAgKi9cbiAgICBzdWJzY3JpYmU6IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcblxuICAgICAgICB2YXIgdG9waWNzID0gW10uY29uY2F0KHRvcGljKTtcbiAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgdmFyIHN1YnNjcmlwdGlvbklkcyA9IFtdO1xuICAgICAgICB2YXIgb3B0cyA9IG1lLmNoYW5uZWxPcHRpb25zO1xuXG4gICAgICAgIG9wdHMudHJhbnNwb3J0LmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICQuZWFjaCh0b3BpY3MsIGZ1bmN0aW9uIChpbmRleCwgdG9waWMpIHtcbiAgICAgICAgICAgICAgICB0b3BpYyA9IG1ha2VOYW1lKG9wdHMuYmFzZSwgb3B0cy50b3BpY1Jlc29sdmVyKHRvcGljKSk7XG4gICAgICAgICAgICAgICAgc3Vic2NyaXB0aW9uSWRzLnB1c2gob3B0cy50cmFuc3BvcnQuc3Vic2NyaWJlKHRvcGljLCBjYWxsYmFjaykpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKHN1YnNjcmlwdGlvbklkc1sxXSA/IHN1YnNjcmlwdGlvbklkcyA6IHN1YnNjcmlwdGlvbklkc1swXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFB1Ymxpc2ggZGF0YSB0byBhIHRvcGljLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlcyoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIFNlbmQgZGF0YSB0byBhbGwgc3Vic2NyaWJlcnMgb2YgdGhlICdydW4nIHRvcGljXG4gICAgICogICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJywgeyBjb21wbGV0ZWQ6IGZhbHNlIH0pO1xuICAgICAqXG4gICAgICogICAgICAvLyBTZW5kIGRhdGEgdG8gYWxsIHN1YnNjcmliZXJzIG9mIHRoZSAncnVuL3ZhcmlhYmxlcycgdG9waWNcbiAgICAgKiAgICAgIGNzLnB1Ymxpc2goJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzJywgeyBwcmljZTogNTAgfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgdG9waWNgIFRvcGljIHRvIHB1Ymxpc2ggdG8uXG4gICAgICogQHBhcmFtICB7Kn0gYGRhdGFgICBEYXRhIHRvIHB1Ymxpc2ggdG8gdG9waWMuXG4gICAgICpcbiAgICAgKi9cbiAgICBwdWJsaXNoOiBmdW5jdGlvbiAodG9waWMsIGRhdGEpIHtcbiAgICAgICAgdmFyIHRvcGljcyA9IFtdLmNvbmNhdCh0b3BpYyk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciByZXR1cm5PYmpzID0gW107XG4gICAgICAgIHZhciBvcHRzID0gbWUuY2hhbm5lbE9wdGlvbnM7XG5cblxuICAgICAgICBvcHRzLnRyYW5zcG9ydC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkLmVhY2godG9waWNzLCBmdW5jdGlvbiAoaW5kZXgsIHRvcGljKSB7XG4gICAgICAgICAgICAgICAgdG9waWMgPSBtYWtlTmFtZShvcHRzLmJhc2UsIG9wdHMudG9waWNSZXNvbHZlcih0b3BpYykpO1xuICAgICAgICAgICAgICAgIGlmICh0b3BpYy5jaGFyQXQodG9waWMubGVuZ3RoIC0gMSkgPT09ICcqJykge1xuICAgICAgICAgICAgICAgICAgICB0b3BpYyA9IHRvcGljLnJlcGxhY2UoL1xcKiskLywgJycpO1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1lvdSBjYW4gY2Fubm90IHB1Ymxpc2ggdG8gY2hhbm5lbHMgd2l0aCB3aWxkY2FyZHMuIFB1Ymxpc2hpbmcgdG8gJywgdG9waWMsICdpbnN0ZWFkJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybk9ianMucHVzaChvcHRzLnRyYW5zcG9ydC5wdWJsaXNoKHRvcGljLCBkYXRhKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiAocmV0dXJuT2Jqc1sxXSA/IHJldHVybk9ianMgOiByZXR1cm5PYmpzWzBdKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVW5zdWJzY3JpYmUgZnJvbSBjaGFuZ2VzIHRvIGEgdG9waWMuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBjcy51bnN1YnNjcmliZSgnc2FtcGxlVG9rZW4nKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgdG9rZW5gIFRoZSB0b2tlbiBmb3IgdG9waWMgaXMgcmV0dXJuZWQgd2hlbiB5b3UgaW5pdGlhbGx5IHN1YnNjcmliZS4gUGFzcyBpdCBoZXJlIHRvIHVuc3Vic2NyaWJlIGZyb20gdGhhdCB0b3BpYy5cbiAgICAgKi9cbiAgICB1bnN1YnNjcmliZTogZnVuY3Rpb24gKHRva2VuKSB7XG4gICAgICAgIHRoaXMuY2hhbm5lbE9wdGlvbnMudHJhbnNwb3J0LnVuc3Vic2NyaWJlKHRva2VuKTtcbiAgICAgICAgcmV0dXJuIHRva2VuO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdGFydCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKlxuICAgICAqIFN1cHBvcnRlZCBldmVudHMgYXJlOiBgY29ubmVjdGAsIGBkaXNjb25uZWN0YCwgYHN1YnNjcmliZWAsIGB1bnN1YnNjcmliZWAsIGBwdWJsaXNoYCwgYGVycm9yYC5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICovXG4gICAgb246IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9uLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0b3AgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICovXG4gICAgb2ZmOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vZmYuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVHJpZ2dlciBldmVudHMgYW5kIGV4ZWN1dGUgaGFuZGxlcnMuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vdHJpZ2dlci8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vdHJpZ2dlci8uXG4gICAgICovXG4gICAgdHJpZ2dlcjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlci5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH1cblxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbDtcbiIsIi8qKlxuICogQGNsYXNzIENvbmZpZ3VyYXRpb25TZXJ2aWNlXG4gKlxuICogQWxsIHNlcnZpY2VzIHRha2UgaW4gYSBjb25maWd1cmF0aW9uIHNldHRpbmdzIG9iamVjdCB0byBjb25maWd1cmUgdGhlbXNlbHZlcy4gQSBKUyBoYXNoIHt9IGlzIGEgdmFsaWQgY29uZmlndXJhdGlvbiBvYmplY3QsIGJ1dCBvcHRpb25hbGx5IHlvdSBjYW4gdXNlIHRoZSBjb25maWd1cmF0aW9uIHNlcnZpY2UgdG8gdG9nZ2xlIGNvbmZpZ3MgYmFzZWQgb24gdGhlIGVudmlyb25tZW50XG4gKlxuICogQGV4YW1wbGVcbiAqICAgICB2YXIgY3MgPSByZXF1aXJlKCdjb25maWd1cmF0aW9uLXNlcnZpY2UnKSh7XG4gKiAgICAgICAgICBkZXY6IHsgLy9lbnZpcm9ubWVudFxuICAgICAgICAgICAgICAgIHBvcnQ6IDMwMDAsXG4gICAgICAgICAgICAgICAgaG9zdDogJ2xvY2FsaG9zdCcsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgcHJvZDoge1xuICAgICAgICAgICAgICAgIHBvcnQ6IDgwODAsXG4gICAgICAgICAgICAgICAgaG9zdDogJ2FwaS5mb3Jpby5jb20nLFxuICAgICAgICAgICAgICAgIGxvZ0xldmVsOiAnbm9uZSdcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBsb2dMZXZlbDogJ0RFQlVHJyAvL2dsb2JhbFxuICogICAgIH0pO1xuICpcbiAqICAgICAgY3MuZ2V0KCdsb2dMZXZlbCcpOyAvL3JldHVybnMgJ0RFQlVHJ1xuICpcbiAqICAgICAgY3Muc2V0RW52KCdkZXYnKTtcbiAqICAgICAgY3MuZ2V0KCdsb2dMZXZlbCcpOyAvL3JldHVybnMgJ0RFQlVHJ1xuICpcbiAqICAgICAgY3Muc2V0RW52KCdwcm9kJyk7XG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdub25lJ1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgdXJsU2VydmljZSA9IHJlcXVpcmUoJy4vdXJsLWNvbmZpZy1zZXJ2aWNlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vVE9ETzogRW52aXJvbm1lbnRzXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICBsb2dMZXZlbDogJ05PTkUnXG4gICAgfTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgc2VydmljZU9wdGlvbnMuc2VydmVyID0gdXJsU2VydmljZShzZXJ2aWNlT3B0aW9ucy5zZXJ2ZXIpO1xuXG4gICAgcmV0dXJuIHtcblxuICAgICAgICBkYXRhOiBzZXJ2aWNlT3B0aW9ucyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IHRoZSBlbnZpcm9ubWVudCBrZXkgdG8gZ2V0IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmcm9tXG4gICAgICAgICAqIEBwYXJhbSB7IHN0cmluZ30gZW52XG4gICAgICAgICAqL1xuICAgICAgICBzZXRFbnY6IGZ1bmN0aW9uIChlbnYpIHtcblxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ30gcHJvcGVydHkgb3B0aW9uYWxcbiAgICAgICAgICogQHJldHVybiB7Kn0gICAgICAgICAgVmFsdWUgb2YgcHJvcGVydHkgaWYgc3BlY2lmaWVkLCB0aGUgZW50aXJlIGNvbmZpZyBvYmplY3Qgb3RoZXJ3aXNlXG4gICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChwcm9wZXJ0eSkge1xuICAgICAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zW3Byb3BlcnR5XTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8T2JqZWN0fSBrZXkgaWYgYSBrZXkgaXMgcHJvdmlkZWQsIHNldCBhIGtleSB0byB0aGF0IHZhbHVlLiBPdGhlcndpc2UgbWVyZ2Ugb2JqZWN0IHdpdGggY3VycmVudCBjb25maWdcbiAgICAgICAgICogQHBhcmFtICB7Kn0gdmFsdWUgIHZhbHVlIGZvciBwcm92aWRlZCBrZXlcbiAgICAgICAgICovXG4gICAgICAgIHNldDogZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH07XG59O1xuXG4iLCIvKipcbiAqICMjRGF0YSBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBEYXRhIEFQSSBTZXJ2aWNlIGFsbG93cyB5b3UgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCBtYW5pcHVsYXRlIGRhdGEgcmVsYXRlZCB0byBhbnkgb2YgeW91ciBwcm9qZWN0cy4gRGF0YSBhcmUgb3JnYW5pemVkIGluIGNvbGxlY3Rpb25zLiBFYWNoIGNvbGxlY3Rpb24gY29udGFpbnMgYSBkb2N1bWVudDsgZWFjaCBlbGVtZW50IG9mIHRoaXMgdG9wLWxldmVsIGRvY3VtZW50IGlzIGEgSlNPTiBvYmplY3QuIChTZWUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBvbiB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pLilcbiAqXG4gKiBBbGwgQVBJIGNhbGxzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBEYXRhIEFQSSBTZXJ2aWNlIGRlZmF1bHRzLiBJbiBwYXJ0aWN1bGFyLCB0aGVyZSBhcmUgdGhyZWUgcmVxdWlyZWQgcGFyYW1ldGVycyB3aGVuIHlvdSBpbnN0YW50aWF0ZSB0aGUgRGF0YSBTZXJ2aWNlOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKiAqIGByb290YDogVGhlIHRoZSBuYW1lIG9mIHRoZSBjb2xsZWN0aW9uLiBJZiB5b3UgaGF2ZSBtdWx0aXBsZSBjb2xsZWN0aW9ucyB3aXRoaW4gZWFjaCBvZiB5b3VyIHByb2plY3RzLCB5b3UgY2FuIGFsc28gcGFzcyB0aGUgY29sbGVjdGlvbiBuYW1lIGFzIGFuIG9wdGlvbiBmb3IgZWFjaCBjYWxsLlxuICpcbiAqICAgICAgIHZhciBkcyA9IG5ldyBGLnNlcnZpY2UuRGF0YSh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgcm9vdDogJ3N1cnZleS1yZXNwb25zZXMnLFxuICogICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMiwgJ3F1ZXN0aW9uMic6IDEwLFxuICogICAgICAgICAgJ3F1ZXN0aW9uMyc6IGZhbHNlLCAncXVlc3Rpb240JzogJ3NvbWV0aW1lcycgfSApO1xuICogICAgICAgZHMuc2F2ZUFzKCd1c2VyMicsXG4gKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAzLCAncXVlc3Rpb24yJzogOCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiB0cnVlLCAncXVlc3Rpb240JzogJ2Fsd2F5cycgfSApO1xuICogICAgICAgZHMucXVlcnkoJycseyAncXVlc3Rpb24yJzogeyAnJGd0JzogOX0gfSk7XG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGByb290YCwgdGhlIERhdGEgU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYW1lIG9mIGNvbGxlY3Rpb24uIERlZmF1bHRzIHRvIGAvYCwgdGhhdCBpcywgdGhlIHJvb3QgbGV2ZWwgb2YgeW91ciBwcm9qZWN0IGF0IGBmb3Jpby5jb20vYXBwL3lvdXItYWNjb3VudC1pZC95b3VyLXByb2plY3QtaWQvYC4gUmVxdWlyZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICByb290OiAnLycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3Igb3BlcmF0aW9ucyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiBzdG9yZS5nZXQoJ2VwaWNlbnRlci5wcm9qZWN0LnRva2VuJykgfHwgJycsXG5cbiAgICAgICAgZG9tYWluOiAnZm9yaW8uY29tJyxcblxuICAgICAgICAvL09wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXJcbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uIChrZXksIHJvb3QpIHtcbiAgICAgICAgaWYgKCFyb290KSB7XG4gICAgICAgICAgICByb290ID0gc2VydmljZU9wdGlvbnMucm9vdDtcbiAgICAgICAgfVxuICAgICAgICB2YXIgdXJsID0gdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2RhdGEnKSArIHF1dGlsLmFkZFRyYWlsaW5nU2xhc2gocm9vdCk7XG4gICAgICAgIGlmIChrZXkpIHtcbiAgICAgICAgICAgIHVybCs9IHF1dGlsLmFkZFRyYWlsaW5nU2xhc2goa2V5KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsO1xuICAgIH07XG5cbiAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogZ2V0VVJMXG4gICAgfSk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIGh0dHBPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2VhcmNoIGZvciBkYXRhIHdpdGhpbiBhIGNvbGxlY3Rpb24uXG4gICAgICAgICAqXG4gICAgICAgICAqIFNlYXJjaGluZyB1c2luZyBjb21wYXJpc29uIG9yIGxvZ2ljYWwgb3BlcmF0b3JzIChhcyBvcHBvc2VkIHRvIGV4YWN0IG1hdGNoZXMpIHJlcXVpcmVzIE1vbmdvREIgc3ludGF4LiBTZWUgdGhlIHVuZGVybHlpbmcgW0RhdGEgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvZGF0YV9hcGkvI3NlYXJjaGluZykgZm9yIGFkZGl0aW9uYWwgZGV0YWlscy5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVxdWVzdCBhbGwgZGF0YSBhc3NvY2lhdGVkIHdpdGggZG9jdW1lbnQgJ3VzZXIxJ1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGV4YWN0IG1hdGNoaW5nOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uIHdoZXJlICdxdWVzdGlvbjInIGlzIDlcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAncXVlc3Rpb24yJzogOX0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGNvbXBhcmlzb24gb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgZ3JlYXRlciB0aGFuIDlcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAncXVlc3Rpb24yJzogeyAnJGd0JzogOX0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbG9naWNhbCBvcGVyYXRvcnM6XG4gICAgICAgICAqICAgICAgLy8gcmVxdWVzdCBhbGwgZG9jdW1lbnRzIGluIGNvbGxlY3Rpb25cbiAgICAgICAgICogICAgICAvLyB3aGVyZSAncXVlc3Rpb24yJyBpcyBsZXNzIHRoYW4gMTAsIGFuZCAncXVlc3Rpb24zJyBpcyBmYWxzZVxuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICckYW5kJzogWyB7ICdxdWVzdGlvbjInOiB7ICckbHQnOjEwfSB9LCB7ICdxdWVzdGlvbjMnOiBmYWxzZSB9XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZWd1bGFyIGV4cHJlc3NzaW9uczogdXNlIGFueSBQZXJsLWNvbXBhdGlibGUgcmVndWxhciBleHByZXNzaW9uc1xuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uNScgY29udGFpbnMgdGhlIHN0cmluZyAnLipkYXknXG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uNSc6IHsgJyRyZWdleCc6ICcuKmRheScgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBrZXlgIFRoZSBuYW1lIG9mIHRoZSBkb2N1bWVudCB0byBzZWFyY2guIFBhc3MgdGhlIGVtcHR5IHN0cmluZyAoJycpIHRvIHNlYXJjaCB0aGUgZW50aXJlIGNvbGxlY3Rpb24uXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcXVlcnlgIFRoZSBxdWVyeSBvYmplY3QuIEZvciBleGFjdCBtYXRjaGluZywgdGhpcyBvYmplY3QgY29udGFpbnMgdGhlIGZpZWxkIG5hbWUgYW5kIGZpZWxkIHZhbHVlIHRvIG1hdGNoLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gY29tcGFyaXNvbiwgdGhpcyBvYmplY3QgY29udGFpbnMgdGhlIGZpZWxkIG5hbWUgYW5kIHRoZSBjb21wYXJpc29uIGV4cHJlc3Npb24uIEZvciBtYXRjaGluZyBiYXNlZCBvbiBsb2dpY2FsIG9wZXJhdG9ycywgdGhpcyBvYmplY3QgY29udGFpbnMgYW4gZXhwcmVzc2lvbiB1c2luZyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGV4YW1wbGVzLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKGtleSwgcXVlcnksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBxOiBxdWVyeSB9LCBvdXRwdXRNb2RpZmllcik7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhbiBhbm9ueW1vdXMgZG9jdW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiAoRG9jdW1lbnRzIGFyZSB0b3AtbGV2ZWwgZWxlbWVudHMgd2l0aGluIGEgY29sbGVjdGlvbi4gQ29sbGVjdGlvbnMgbXVzdCBiZSB1bmlxdWUgd2l0aGluIHRoaXMgYWNjb3VudCAodGVhbSBvciBwZXJzb25hbCBhY2NvdW50KSBhbmQgcHJvamVjdCBhbmQgYXJlIHNldCB3aXRoIHRoZSBgcm9vdGAgZmllbGQgaW4gdGhlIGBvcHRpb25gIHBhcmFtZXRlci4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLykgZm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMuc2F2ZSgncXVlc3Rpb24xJywgJ3llcycpO1xuICAgICAgICAgKiAgICAgIGRzLnNhdmUoe3F1ZXN0aW9uMToneWVzJywgcXVlc3Rpb24yOiAzMiB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHsgbmFtZTonSm9obicsIGNsYXNzTmFtZTogJ0NTMTAxJyB9LCB7IHJvb3Q6ICdzdHVkZW50cycgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYGtleWAgSWYgYGtleWAgaXMgYSBzdHJpbmcsIGl0IGlzIHRoZSBpZCBvZiB0aGUgZWxlbWVudCB0byBzYXZlIChjcmVhdGUpIGluIHRoaXMgZG9jdW1lbnQuIElmIGBrZXlgIGlzIGFuIG9iamVjdCwgdGhlIG9iamVjdCBpcyB0aGUgZGF0YSB0byBzYXZlIChjcmVhdGUpIGluIHRoaXMgZG9jdW1lbnQuIEluIGJvdGggY2FzZXMsIHRoZSBpZCBmb3IgdGhlIGRvY3VtZW50IGlzIGdlbmVyYXRlZCBhdXRvbWF0aWNhbGx5LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUuIElmIGBrZXlgIGlzIGEgc3RyaW5nLCB0aGlzIGlzIHRoZSB2YWx1ZSB0byBzYXZlLiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSB2YWx1ZShzKSB0byBzYXZlIGFyZSBhbHJlYWR5IHBhcnQgb2YgYGtleWAgYW5kIHRoaXMgYXJndW1lbnQgaXMgbm90IHJlcXVpcmVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzYXZlOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGF0dHJzO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBrZXkgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbHVlO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAoYXR0cnMgPSB7fSlba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTCgnJywgaHR0cE9wdGlvbnMucm9vdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBkYXRhIHRvIGEgbmFtZWQgZG9jdW1lbnQgb3IgZWxlbWVudCB3aXRoaW4gdGhlIGNvbGxlY3Rpb24uIFRoZSBgcm9vdGAgb2YgdGhlIGNvbGxlY3Rpb24gbXVzdCBiZSBzcGVjaWZpZWQgc2VwYXJhdGVseSBpbiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGVpdGhlciBhcyBwYXJ0IG9mIHRoZSBjYWxsIG9yIGFzIHBhcnQgb2YgdGhlIGluaXRpYWxpemF0aW9uIG9mIGRzLlxuICAgICAgICAgKlxuICAgICAgICAgKiAoRG9jdW1lbnRzIGFyZSB0b3AtbGV2ZWwgZWxlbWVudHMgd2l0aGluIGEgY29sbGVjdGlvbi4gQ29sbGVjdGlvbnMgbXVzdCBiZSB1bmlxdWUgd2l0aGluIHRoaXMgYWNjb3VudCAodGVhbSBvciBwZXJzb25hbCBhY2NvdW50KSBhbmQgcHJvamVjdCBhbmQgYXJlIHNldCB3aXRoIHRoZSBgcm9vdGAgZmllbGQgaW4gdGhlIGBvcHRpb25gIHBhcmFtZXRlci4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLykgZm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCd1c2VyMScsXG4gICAgICAgICAqICAgICAgICAgIHsgJ3F1ZXN0aW9uMSc6IDIsICdxdWVzdGlvbjInOiAxMCxcbiAgICAgICAgICogICAgICAgICAgICdxdWVzdGlvbjMnOiBmYWxzZSwgJ3F1ZXN0aW9uNCc6ICdzb21ldGltZXMnIH0gKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ3N0dWRlbnQxJyxcbiAgICAgICAgICogICAgICAgICAgeyBmaXJzdE5hbWU6ICdqb2huJywgbGFzdE5hbWU6ICdzbWl0aCcgfSxcbiAgICAgICAgICogICAgICAgICAgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygnbWdtdDEwMC9ncm91cEInLFxuICAgICAgICAgKiAgICAgICAgICB7IHNjZW5hcmlvWWVhcjogJzIwMTUnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ215Y2xhc3NlcycgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBJZCBvZiB0aGUgZG9jdW1lbnQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgdmFsdWVgIChPcHRpb25hbCkgVGhlIGRhdGEgdG8gc2F2ZSwgaW4ga2V5OnZhbHVlIHBhaXJzLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzYXZlQXM6IGZ1bmN0aW9uIChrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnB1dCh2YWx1ZSwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgZGF0YSBmb3IgYSBzcGVjaWZpYyBkb2N1bWVudCBvciBmaWVsZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMScpO1xuICAgICAgICAgKiAgICAgIGRzLmxvYWQoJ3VzZXIxL3F1ZXN0aW9uMycpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBga2V5YCBUaGUgaWQgb2YgdGhlIGRhdGEgdG8gcmV0dXJuLiBDYW4gYmUgdGhlIGlkIG9mIGEgZG9jdW1lbnQsIG9yIGEgcGF0aCB0byBkYXRhIHdpdGhpbiB0aGF0IGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKGtleSwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5LCBodHRwT3B0aW9ucy5yb290KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChvdXRwdXRNb2RpZmllciwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIGRhdGEgZnJvbSBjb2xsZWN0aW9uLiBPbmx5IGRvY3VtZW50cyAodG9wLWxldmVsIGVsZW1lbnRzIGluIGVhY2ggY29sbGVjdGlvbikgY2FuIGJlIGRlbGV0ZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICBkcy5yZW1vdmUoJ3VzZXIxJyk7XG4gICAgICAgICAqXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfEFycmF5fSBga2V5c2AgVGhlIGlkIG9mIHRoZSBkb2N1bWVudCB0byByZW1vdmUgZnJvbSB0aGlzIGNvbGxlY3Rpb24sIG9yIGFuIGFycmF5IG9mIHN1Y2ggaWRzLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXlzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHBhcmFtcztcbiAgICAgICAgICAgIGlmICgkLmlzQXJyYXkoa2V5cykpIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSB7IGlkOiBrZXlzIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHBhcmFtcyA9ICcnO1xuICAgICAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXlzLCBodHRwT3B0aW9ucy5yb290KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBodHRwLmRlbGV0ZShwYXJhbXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVwaWNlbnRlciBkb2Vzbid0IGFsbG93IG51a2luZyBjb2xsZWN0aW9uc1xuICAgICAgICAvLyAgICAgLyoqXG4gICAgICAgIC8vICAgICAgKiBSZW1vdmVzIGNvbGxlY3Rpb24gYmVpbmcgcmVmZXJlbmNlZFxuICAgICAgICAvLyAgICAgICogQHJldHVybiBudWxsXG4gICAgICAgIC8vICAgICAgKi9cbiAgICAgICAgLy8gICAgIGRlc3Ryb3k6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIC8vICAgICAgICAgcmV0dXJuIHRoaXMucmVtb3ZlKCcnLCBvcHRpb25zKTtcbiAgICAgICAgLy8gICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI01lbWJlciBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBNZW1iZXIgQVBJIEFkYXB0ZXIgcHJvdmlkZXMgbWV0aG9kcyB0byBsb29rIHVwIGluZm9ybWF0aW9uIGFib3V0IGVuZCB1c2VycyBmb3IgeW91ciBwcm9qZWN0IGFuZCBob3cgdGhleSBhcmUgZGl2aWRlZCBhY3Jvc3MgZ3JvdXBzLiBJdCBpcyBiYXNlZCBvbiBxdWVyeSBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbTWVtYmVyIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL3VzZXJfbWFuYWdlbWVudC9tZW1iZXIvKS5cbiAqXG4gKiBUaGlzIGlzIG9ubHkgbmVlZGVkIGZvciBBdXRoZW50aWNhdGVkIHByb2plY3RzLCB0aGF0IGlzLCB0ZWFtIHByb2plY3RzIHdpdGggW2VuZCB1c2VycyBhbmQgZ3JvdXBzXSguLi8uLi8uLi9ncm91cHNfYW5kX2VuZF91c2Vycy8pLiBGb3IgZXhhbXBsZSwgaWYgc29tZSBvZiB5b3VyIGVuZCB1c2VycyBhcmUgZmFjaWxpdGF0b3JzLCBvciBpZiB5b3VyIGVuZCB1c2VycyBzaG91bGQgYmUgdHJlYXRlZCBkaWZmZXJlbnRseSBiYXNlZCBvbiB3aGljaCBncm91cCB0aGV5IGFyZSBpbiwgdXNlIHRoZSBNZW1iZXIgQVBJIHRvIGZpbmQgdGhhdCBpbmZvcm1hdGlvbi5cbiAqXG4gKiAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJ2I2YjMxM2EzLWFiODQtNDc5Yy1iYWVhLTIwNmY2YmZmMzM3JyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKHsgZ3JvdXBJZDogJzAwYjUzMzA4LTk4MzMtNDdmMi1iMjFlLTEyNzhjMDdkNTNiOCcgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgYXBpRW5kcG9pbnQgPSAnbWVtYmVyL2xvY2FsJztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIHVzZXIgaWQuIERlZmF1bHRzIHRvIGEgYmxhbmsgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdXNlcklkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIGdyb3VwIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy4gTm90ZSB0aGF0IHRoaXMgaXMgdGhlIGdyb3VwICppZCosIG5vdCB0aGUgZ3JvdXAgKm5hbWUqLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXBJZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zLCBzZXJ2aWNlT3B0aW9ucyk7XG5cbiAgICB2YXIgZ2V0RmluYWxQYXJhbXMgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgIGlmICh0eXBlb2YgcGFyYW1zID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBwYXJhbXMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICB9O1xuXG4gICAgdmFyIHBhdGNoVXNlckFjdGl2ZUZpZWxkID0gZnVuY3Rpb24gKHBhcmFtcywgYWN0aXZlLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLCB7XG4gICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHBhcmFtcy5ncm91cElkICsgJy8nICsgcGFyYW1zLnVzZXJJZFxuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gaHR0cC5wYXRjaCh7IGFjdGl2ZTogYWN0aXZlIH0sIGh0dHBPcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGFsbCBvZiB0aGUgZ3JvdXAgbWVtYmVyc2hpcHMgZm9yIG9uZSBlbmQgdXNlci4gVGhlIG1lbWJlcnNoaXAgZGV0YWlscyBhcmUgcmV0dXJuZWQgaW4gYW4gYXJyYXksIHdpdGggb25lIGVsZW1lbnQgKGdyb3VwIHJlY29yZCkgZm9yIGVhY2ggZ3JvdXAgdG8gd2hpY2ggdGhlIGVuZCB1c2VyIGJlbG9uZ3MuXG4gICAgICAgICpcbiAgICAgICAgKiBJbiB0aGUgbWVtYmVyc2hpcCBhcnJheSwgZWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGlkLCBwcm9qZWN0IGlkLCBhY2NvdW50ICh0ZWFtKSBpZCwgYW5kIGFuIGFycmF5IG9mIG1lbWJlcnMuIEhvd2V2ZXIsIG9ubHkgdGhlIHVzZXIgd2hvc2UgdXNlcklkIGlzIGluY2x1ZGVkIGluIHRoZSBjYWxsIGlzIGxpc3RlZCBpbiB0aGUgbWVtYmVycyBhcnJheSAocmVnYXJkbGVzcyBvZiB3aGV0aGVyIHRoZXJlIGFyZSBvdGhlciBtZW1iZXJzIGluIHRoaXMgZ3JvdXApLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cHNGb3JVc2VyKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbihtZW1iZXJzaGlwcyl7XG4gICAgICAgICogICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7IGk8bWVtYmVyc2hpcHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhtZW1iZXJzaGlwc1tpXS5ncm91cElkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIH1cbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cHNGb3JVc2VyKHsgdXNlcklkOiAnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fSBgcGFyYW1zYCBUaGUgdXNlciBpZCBmb3IgdGhlIGVuZCB1c2VyLiBBbHRlcm5hdGl2ZWx5LCBhbiBvYmplY3Qgd2l0aCBmaWVsZCBgdXNlcklkYCBhbmQgdmFsdWUgdGhlIHVzZXIgaWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuXG4gICAgICAgIGdldEdyb3Vwc0ZvclVzZXI6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGlzU3RyaW5nID0gdHlwZW9mIHBhcmFtcyA9PT0gJ3N0cmluZyc7XG4gICAgICAgICAgICB2YXIgb2JqUGFyYW1zID0gZ2V0RmluYWxQYXJhbXMocGFyYW1zKTtcbiAgICAgICAgICAgIGlmICghaXNTdHJpbmcgJiYgIW9ialBhcmFtcy51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHVzZXJJZCBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBnZXRQYXJtcyA9IGlzU3RyaW5nID8geyB1c2VySWQ6IHBhcmFtcyB9IDogX3BpY2sob2JqUGFyYW1zLCAndXNlcklkJyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoZ2V0UGFybXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IG9uZSBncm91cCwgaW5jbHVkaW5nIGFuIGFycmF5IG9mIGFsbCBpdHMgbWVtYmVycy5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKCc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbihncm91cCl7XG4gICAgICAgICogICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7IGk8Z3JvdXAubWVtYmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICAqICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGdyb3VwLm1lbWJlcnNbaV0udXNlck5hbWUpO1xuICAgICAgICAqICAgICAgICAgICAgICAgfVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIG1hLmdldEdyb3VwRGV0YWlscyh7IGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ3xvYmplY3R9IGBwYXJhbXNgIFRoZSBncm91cCBpZC4gQWx0ZXJuYXRpdmVseSwgYW4gb2JqZWN0IHdpdGggZmllbGQgYGdyb3VwSWRgIGFuZCB2YWx1ZSB0aGUgZ3JvdXAgaWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBnZXRHcm91cERldGFpbHM6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgdmFyIGlzU3RyaW5nID0gdHlwZW9mIHBhcmFtcyA9PT0gJ3N0cmluZyc7XG4gICAgICAgICAgICB2YXIgb2JqUGFyYW1zID0gZ2V0RmluYWxQYXJhbXMocGFyYW1zKTtcbiAgICAgICAgICAgIGlmICghaXNTdHJpbmcgJiYgIW9ialBhcmFtcy5ncm91cElkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBncm91cElkIHNwZWNpZmllZC4nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGdyb3VwSWQgPSBpc1N0cmluZyA/IHBhcmFtcyA6IG9ialBhcmFtcy5ncm91cElkO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgZ3JvdXBJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoe30sIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBTZXQgYSBwYXJ0aWN1bGFyIGVuZCB1c2VyIGFzIGBhY3RpdmVgLiBBY3RpdmUgZW5kIHVzZXJzIGNhbiBiZSBhc3NpZ25lZCB0byBbd29ybGRzXSguLi93b3JsZC1tYW5hZ2VyLykgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZHVyaW5nIGF1dG9tYXRpYyBhc3NpZ25tZW50LlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5tYWtlVXNlckFjdGl2ZSh7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFRoZSBlbmQgdXNlciBhbmQgZ3JvdXAgaW5mb3JtYXRpb24uXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMudXNlcklkYCBUaGUgaWQgb2YgdGhlIGVuZCB1c2VyIHRvIG1ha2UgYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggdGhpcyBlbmQgdXNlciBiZWxvbmdzLCBhbmQgaW4gd2hpY2ggdGhlIGVuZCB1c2VyIHNob3VsZCBiZWNvbWUgYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgbWFrZVVzZXJBY3RpdmU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXRjaFVzZXJBY3RpdmVGaWVsZChwYXJhbXMsIHRydWUsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFNldCBhIHBhcnRpY3VsYXIgZW5kIHVzZXIgYXMgYGluYWN0aXZlYC4gSW5hY3RpdmUgZW5kIHVzZXJzIGFyZSBub3QgYXNzaWduZWQgdG8gW3dvcmxkc10oLi4vd29ybGQtbWFuYWdlci8pIGluIG11bHRpcGxheWVyIGdhbWVzIGR1cmluZyBhdXRvbWF0aWMgYXNzaWdubWVudC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEubWFrZVVzZXJJbmFjdGl2ZSh7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFRoZSBlbmQgdXNlciBhbmQgZ3JvdXAgaW5mb3JtYXRpb24uXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMudXNlcklkYCBUaGUgaWQgb2YgdGhlIGVuZCB1c2VyIHRvIG1ha2UgaW5hY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZ3JvdXBJZGAgVGhlIGlkIG9mIHRoZSBncm91cCB0byB3aGljaCB0aGlzIGVuZCB1c2VyIGJlbG9uZ3MsIGFuZCBpbiB3aGljaCB0aGUgZW5kIHVzZXIgc2hvdWxkIGJlY29tZSBpbmFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIG1ha2VVc2VySW5hY3RpdmU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXRjaFVzZXJBY3RpdmVGaWVsZChwYXJhbXMsIGZhbHNlLCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICpcbiAqICMjUnVuIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIFJ1biBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIHBlcmZvcm0gY29tbW9uIHRhc2tzIGFyb3VuZCBjcmVhdGluZyBhbmQgdXBkYXRpbmcgcnVucywgdmFyaWFibGVzLCBhbmQgZGF0YS5cbiAqXG4gKiBXaGVuIGJ1aWxkaW5nIGludGVyZmFjZXMgdG8gc2hvdyBydW4gb25lIGF0IGEgdGltZSAoYXMgZm9yIHN0YW5kYXJkIGVuZCB1c2VycyksIHR5cGljYWxseSB5b3UgZmlyc3QgaW5zdGFudGlhdGUgYSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgYW5kIHRoZW4gYWNjZXNzIHRoZSBSdW4gU2VydmljZSB0aGF0IGlzIGF1dG9tYXRpY2FsbHkgcGFydCBvZiB0aGUgbWFuYWdlciwgcmF0aGVyIHRoYW4gaW5zdGFudGlhdGluZyB0aGUgUnVuIFNlcnZpY2UgZGlyZWN0bHkuIFRoaXMgaXMgYmVjYXVzZSB0aGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGNvbnRyb2wgb3ZlciBydW4gY3JlYXRpb24gZGVwZW5kaW5nIG9uIHJ1biBzdGF0ZXMuXG4gKlxuICogSG93ZXZlciwgbWFueSBvZiB0aGUgRXBpY2VudGVyIHNhbXBsZSBwcm9qZWN0cyB1c2UgYSBSdW4gU2VydmljZSwgYmVjYXVzZSBnZW5lcmFsbHkgdGhlIHNhbXBsZSBwcm9qZWN0cyBhcmUgcGxheWVkIGluIG9uZSBlbmQgdXNlciBzZXNzaW9uIGFuZCBkb24ndCBjYXJlIGFib3V0IHJ1biBzdGF0ZXMgb3IgW3J1biBzdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pLiBUaGUgUnVuIEFQSSBTZXJ2aWNlIGlzIGFsc28gdXNlZnVsIGZvciBidWlsZGluZyBhbiBpbnRlcmZhY2UgZm9yIGEgZmFjaWxpdGF0b3IsIGJlY2F1c2UgaXQgbWFrZXMgaXQgZWFzeSB0byBsaXN0IGRhdGEgYWNyb3NzIG11bHRpcGxlIHJ1bnMgKHVzaW5nIHRoZSBgZmlsdGVyKClgIGFuZCBgcXVlcnkoKWAgbWV0aG9kcykuXG4gKlxuICogVG8gdXNlIHRoZSBSdW4gQVBJIFNlcnZpY2UsIGluc3RhbnRpYXRlIGl0IGJ5IHBhc3NpbmcgaW46XG4gKlxuICogKiBgYWNjb3VudGA6IEVwaWNlbnRlciBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cywgKipVc2VyIElEKiogZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiAqICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiAqXG4gKiBGb3IgZXhhbXBsZSxcbiAqXG4gKiAgICAgICB2YXIgcnMgPSBuZXcgRi5zZXJ2aWNlLlJ1bih7XG4gKiAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgfSk7XG4gKiAgICAgIHJzLmNyZWF0ZSgnc3VwcGx5X2NoYWluX2dhbWUucHknKS50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgfSk7XG4gKlxuICpcbiAqIEFkZGl0aW9uYWxseSwgYWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgUnVuIEFQSSBTZXJ2aWNlIGRlZmF1bHRzIGxpc3RlZCBiZWxvdy5cbiAqXG4gKiBOb3RlIHRoYXQgaW4gYWRkaXRpb24gdG8gdGhlIGBhY2NvdW50YCwgYHByb2plY3RgLCBhbmQgYG1vZGVsYCwgdGhlIFJ1biBTZXJ2aWNlIHBhcmFtZXRlcnMgb3B0aW9uYWxseSBpbmNsdWRlIGEgYHNlcnZlcmAgb2JqZWN0LCB3aG9zZSBgaG9zdGAgZmllbGQgY29udGFpbnMgdGhlIFVSSSBvZiB0aGUgRm9yaW8gc2VydmVyLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0LCBidXQgeW91IGNhbiBwYXNzIGl0IGV4cGxpY2l0bHkgaWYgZGVzaXJlZC4gSXQgaXMgbW9zdCBjb21tb25seSB1c2VkIGZvciBjbGFyaXR5IHdoZW4geW91IGFyZSBbaG9zdGluZyBhbiBFcGljZW50ZXIgcHJvamVjdCBvbiB5b3VyIG93biBzZXJ2ZXJdKC4uLy4uLy4uL2hvd190by9zZWxmX2hvc3RpbmcvKS5cbiAqXG4gKiAgICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5X2NoYWluX2dhbWUucHknLFxuICogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiAqICAgICAgICAgICB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIHJtLmdldFJ1bigpXG4gKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuKSB7XG4gKiAgICAgICAgICAgICAgIC8vIHRoZSBSdW5NYW5hZ2VyLnJ1biBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuICogICAgICAgICAgICAgICAvLyBzbyBhbnkgUnVuIFNlcnZpY2UgbWV0aG9kIGlzIHZhbGlkIGhlcmVcbiAqICAgICAgICAgICAgICAgdmFyIHJzID0gcm0ucnVuO1xuICogICAgICAgICAgICAgICBycy5kbygnc29tZU9wZXJhdGlvbicpO1xuICogICAgICAgfSlcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBydXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcnVuLXV0aWwnKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBWYXJpYWJsZXNTZXJ2aWNlID0gcmVxdWlyZSgnLi92YXJpYWJsZXMtYXBpLXNlcnZpY2UnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgLy8gY29uZmlnIHx8IChjb25maWcgPSBjb25maWdTZXJ2aWNlLmdldCgpKTtcbiAgICB2YXIgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkoeyBzeW5jaHJvbm91czogdHJ1ZSB9KTtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiBzdG9yZS5nZXQoJ2VwaWNlbnRlci5wcm9qZWN0LnRva2VuJykgfHwgc3RvcmUuZ2V0KCdlcGljZW50ZXIudG9rZW4nKSB8fCAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvamVjdDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyaXRlcmlhIGJ5IHdoaWNoIHRvIGZpbHRlciBydW5zLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBmaWx0ZXI6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZW5pZW5jZSBhbGlhcyBmb3IgZmlsdGVyLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgaWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGbGFnIGRldGVybWluZXMgaWYgYFgtQXV0b1Jlc3RvcmU6IHRydWVgIGhlYWRlciBpcyBzZW50IHRvIEVwaWNlbnRlci4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGF1dG9SZXN0b3JlOiB0cnVlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3AsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG5cbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmlkKSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmlkO1xuICAgIH1cblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHVybENvbmZpZy5maWx0ZXIgPSAnOyc7XG4gICAgdXJsQ29uZmlnLmdldEZpbHRlclVSTCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdydW4nKTtcbiAgICAgICAgdmFyIGZpbHRlciA9IHF1dGlsLnRvTWF0cml4Rm9ybWF0KHNlcnZpY2VPcHRpb25zLmZpbHRlcik7XG5cbiAgICAgICAgaWYgKGZpbHRlcikge1xuICAgICAgICAgICAgdXJsICs9IGZpbHRlciArICcvJztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsO1xuICAgIH07XG5cbiAgICB1cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgZmlsdGVyID0gc2VydmljZU9wdGlvbnMuZmlsdGVyO1xuICAgICAgICAvLyBUaGUgc2VtaWNvbG9uIHNlcGFyYXRlZCBmaWx0ZXIgaXMgdXNlZCB3aGVuIGZpbHRlciBpcyBhbiBvYmplY3RcbiAgICAgICAgdmFyIGlzRmlsdGVyUnVuSWQgPSBmaWx0ZXIgJiYgJC50eXBlKGZpbHRlcikgPT09ICdzdHJpbmcnO1xuICAgICAgICBpZiAoc2VydmljZU9wdGlvbnMuYXV0b1Jlc3RvcmUgJiYgaXNGaWx0ZXJSdW5JZCkge1xuICAgICAgICAgICAgLy8gQnkgZGVmYXVsdCBhdXRvcmVwbGF5IHRoZSBydW4gYnkgc2VuZGluZyB0aGlzIGhlYWRlciB0byBlcGljZW50ZXJcbiAgICAgICAgICAgIC8vIGh0dHBzOi8vZm9yaW8uY29tL2VwaWNlbnRlci9kb2NzL3B1YmxpYy9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI3JldHJpZXZpbmdcbiAgICAgICAgICAgIHZhciBhdXRvcmVzdG9yZU9wdHMgPSB7XG4gICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICAnWC1BdXRvUmVzdG9yZSc6IHRydWVcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIGF1dG9yZXN0b3JlT3B0cywgb3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gb3B0aW9ucztcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRGaWx0ZXJVUkxcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICBodHRwLnNwbGl0R2V0ID0gcnV0aWwuc3BsaXRHZXRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBzZXRGaWx0ZXJPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAob3B0aW9ucy5pZCkge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5pZDtcbiAgICAgICAgfVxuICAgICAgICBpZiAob3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuZmlsdGVyO1xuICAgICAgICB9XG4gICAgICAgIGlmICghc2VydmljZU9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGZpbHRlciBzcGVjaWZpZWQgdG8gYXBwbHkgb3BlcmF0aW9ucyBhZ2FpbnN0Jyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FzeW5jQVBJID0ge1xuICAgICAgICB1cmxDb25maWc6IHVybENvbmZpZyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JlYXRlIGEgbmV3IHJ1bi5cbiAgICAgICAgICpcbiAgICAgICAgICogTk9URTogVHlwaWNhbGx5IHRoaXMgaXMgbm90IHVzZWQhIFVzZSBgUnVuTWFuYWdlci5nZXRSdW4oKWAgd2l0aCBhIGBzdHJhdGVneWAgb2YgYGFsd2F5cy1uZXdgLCBvciB1c2UgYFJ1bk1hbmFnZXIucmVzZXQoKWAuIFNlZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgZm9yIG1vcmUgZGV0YWlscy5cbiAgICAgICAgICpcbiAgICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgcnMuY3JlYXRlKCdoZWxsb193b3JsZC5qbCcpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd8T2JqZWN0fSBgcGFyYW1zYCBJZiBhIHN0cmluZywgdGhlIG5hbWUgb2YgdGhlIHByaW1hcnkgW21vZGVsIGZpbGVdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pLiBUaGlzIGlzIHRoZSBvbmUgZmlsZSBpbiB0aGUgcHJvamVjdCB0aGF0IGV4cGxpY2l0bHkgZXhwb3NlcyB2YXJpYWJsZXMgYW5kIG1ldGhvZHMsIGFuZCBpdCBtdXN0IGJlIHN0b3JlZCBpbiB0aGUgTW9kZWwgZm9sZGVyIG9mIHlvdXIgRXBpY2VudGVyIHByb2plY3QuIElmIGFuIG9iamVjdCwgbWF5IGluY2x1ZGUgYG1vZGVsYCwgYHNjb3BlYCwgYW5kIGBmaWxlc2AuIChTZWUgdGhlIFtSdW4gTWFuYWdlcl0oLi4vcnVuX21hbmFnZXIvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBgc2NvcGVgIGFuZCBgZmlsZXNgLilcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdydW4nKSB9KTtcbiAgICAgICAgICAgIHZhciBydW5BcGlQYXJhbXMgPSBbJ21vZGVsJywgJ3Njb3BlJywgJ2ZpbGVzJ107XG4gICAgICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAvLyB0aGlzIGlzIGp1c3QgdGhlIG1vZGVsIG5hbWVcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSB7IG1vZGVsOiBwYXJhbXMgfTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zLCBydW5BcGlQYXJhbXMpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IGNyZWF0ZU9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgICAgIGNyZWF0ZU9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJlc3BvbnNlLmlkOyAvL2FsbCBmdXR1cmUgY2hhaW5lZCBjYWxscyB0byBvcGVyYXRlIG9uIHRoaXMgaWRcbiAgICAgICAgICAgICAgICByZXR1cm4gb2xkU3VjY2Vzcy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZXR1cm5zIHBhcnRpY3VsYXIgcnVucywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxc2Agb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiBUaGUgZWxlbWVudHMgb2YgdGhlIGBxc2Agb2JqZWN0IGFyZSBBTkRlZCB0b2dldGhlciB3aXRoaW4gYSBzaW5nbGUgY2FsbCB0byBgLnF1ZXJ5KClgLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJldHVybnMgcnVucyB3aXRoIHNhdmVkID0gdHJ1ZSBhbmQgdmFyaWFibGVzLnByaWNlID4gMSxcbiAgICAgICAgICogICAgICAvLyB3aGVyZSB2YXJpYWJsZXMucHJpY2UgaGFzIGJlZW4gcGVyc2lzdGVkIChyZWNvcmRlZClcbiAgICAgICAgICogICAgICAvLyBpbiB0aGUgbW9kZWwuXG4gICAgICAgICAqICAgICBycy5xdWVyeSh7XG4gICAgICAgICAqICAgICAgICAgICdzYXZlZCc6ICd0cnVlJyxcbiAgICAgICAgICogICAgICAgICAgJy5wcmljZSc6ICc+MSdcbiAgICAgICAgICogICAgICAgfSxcbiAgICAgICAgICogICAgICAge1xuICAgICAgICAgKiAgICAgICAgICBzdGFydHJlY29yZDogMixcbiAgICAgICAgICogICAgICAgICAgZW5kcmVjb3JkOiA1XG4gICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHFzYCBRdWVyeSBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIFF1ZXJ5aW5nIGZvciB2YXJpYWJsZXMgaXMgYXZhaWxhYmxlIGZvciBydW5zIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpIGFuZCBmb3IgcnVucyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBpZiB0aGUgdmFyaWFibGVzIGFyZSBwZXJzaXN0ZWQgKGUuZy4gdGhhdCBoYXZlIGJlZW4gYHJlY29yZGBlZCBpbiB5b3VyIEp1bGlhIG1vZGVsKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChxcywgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHFzOyAvL3Nob3VsZG4ndCBiZSBhYmxlIHRvIG92ZXItcmlkZVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuc3BsaXRHZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogU2ltaWxhciB0byBgLnF1ZXJ5KClgLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGZpbHRlcmAgRmlsdGVyIG9iamVjdC4gRWFjaCBrZXkgY2FuIGJlIGEgcHJvcGVydHkgb2YgdGhlIHJ1biBvciB0aGUgbmFtZSBvZiB2YXJpYWJsZSB0aGF0IGhhcyBiZWVuIHNhdmVkIGluIHRoZSBydW4gKHByZWZhY2VkIGJ5IGB2YXJpYWJsZXMuYCkuIEVhY2ggdmFsdWUgY2FuIGJlIGEgbGl0ZXJhbCB2YWx1ZSwgb3IgYSBjb21wYXJpc29uIG9wZXJhdG9yIGFuZCB2YWx1ZS4gKFNlZSBbbW9yZSBvbiBmaWx0ZXJpbmddKC4uLy4uLy4uL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaS8jZmlsdGVycykgYWxsb3dlZCBpbiB0aGUgdW5kZXJseWluZyBSdW4gQVBJLikgRmlsdGVyaW5nIGZvciB2YXJpYWJsZXMgaXMgYXZhaWxhYmxlIGZvciBydW5zIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpIGFuZCBmb3IgcnVucyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBpZiB0aGUgdmFyaWFibGVzIGFyZSBwZXJzaXN0ZWQgKGUuZy4gdGhhdCBoYXZlIGJlZW4gYHJlY29yZGBlZCBpbiB5b3VyIEp1bGlhIG1vZGVsKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiBmdW5jdGlvbiAoZmlsdGVyLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpKSB7XG4gICAgICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMuZmlsdGVyLCBmaWx0ZXIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBmaWx0ZXI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSB1cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuc3BsaXRHZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgcnVuLiBUaGlzIGluY2x1ZGVzIHN0YW5kYXJkIHJ1biBkYXRhIHN1Y2ggYXMgdGhlIGFjY291bnQsIG1vZGVsLCBwcm9qZWN0LCBhbmQgY3JlYXRlZCBhbmQgbGFzdCBtb2RpZmllZCBkYXRlcy4gVG8gcmVxdWVzdCBzcGVjaWZpYyBtb2RlbCB2YXJpYWJsZXMsIHBhc3MgdGhlbSBhcyBwYXJ0IG9mIHRoZSBgZmlsdGVyc2AgcGFyYW1ldGVyLlxuICAgICAgICAgKlxuICAgICAgICAgKiBOb3RlIHRoYXQgaWYgdGhlIHJ1biBpcyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSwgYW55IG1vZGVsIHZhcmlhYmxlcyBhcmUgYXZhaWxhYmxlOyBpZiB0aGUgcnVuIGlzIFtpbiB0aGUgZGF0YWJhc2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1kYiksIG9ubHkgbW9kZWwgdmFyaWFibGVzIHRoYXQgaGF2ZSBiZWVuIHBlcnNpc3RlZCAmbWRhc2g7IHRoYXQgaXMsIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCAmbWRhc2g7IGFyZSBhdmFpbGFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICBycy5sb2FkKCdiYjU4OTY3Ny1kNDc2LTQ5NzEtYTY4ZS0wYzU4ZDE5MWU0NTAnLCB7IGluY2x1ZGU6IFsnLnByaWNlJywgJy5zYWxlcyddIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHJ1bklEYCBUaGUgcnVuIGlkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGZpbHRlcnNgIChPcHRpb25hbCkgT2JqZWN0IGNvbnRhaW5pbmcgZmlsdGVycyBhbmQgb3BlcmF0aW9uIG1vZGlmaWVycy4gVXNlIGtleSBgaW5jbHVkZWAgdG8gbGlzdCBtb2RlbCB2YXJpYWJsZXMgdGhhdCB5b3Ugd2FudCB0byBpbmNsdWRlIGluIHRoZSByZXNwb25zZS4gT3RoZXIgYXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChydW5JRCwgZmlsdGVycywgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHJ1bklEKSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gcnVuSUQ7IC8vc2hvdWxkbid0IGJlIGFibGUgdG8gb3Zlci1yaWRlXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSB1cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGF0dHJpYnV0ZXMgKGRhdGEsIG1vZGVsIHZhcmlhYmxlcykgb2YgdGhlIHJ1bi5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyBhZGQgJ2NvbXBsZXRlZCcgZmllbGQgdG8gcnVuIHJlY29yZFxuICAgICAgICAgKiAgICAgcnMuc2F2ZSh7IGNvbXBsZXRlZDogdHJ1ZSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIC8vIHVwZGF0ZSAnc2F2ZWQnIGZpZWxkIG9mIHJ1biByZWNvcmQsIGFuZCB1cGRhdGUgdmFsdWVzIG9mIG1vZGVsIHZhcmlhYmxlcyBmb3IgdGhpcyBydW5cbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBzYXZlZDogdHJ1ZSwgdmFyaWFibGVzOiB7IGE6IDIzLCBiOiAyMyB9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGF0dHJpYnV0ZXNgIFRoZSBydW4gZGF0YSBhbmQgdmFyaWFibGVzIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgYXR0cmlidXRlcy52YXJpYWJsZXNgIE1vZGVsIHZhcmlhYmxlcyBtdXN0IGJlIGluY2x1ZGVkIGluIGEgYHZhcmlhYmxlc2AgZmllbGQgd2l0aGluIHRoZSBgYXR0cmlidXRlc2Agb2JqZWN0LiAoT3RoZXJ3aXNlIHRoZXkgYXJlIHRyZWF0ZWQgYXMgcnVuIGRhdGEgYW5kIGFkZGVkIHRvIHRoZSBydW4gcmVjb3JkIGRpcmVjdGx5LilcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGF0dHJpYnV0ZXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goYXR0cmlidXRlcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIGEgbWV0aG9kIGZyb20gdGhlIG1vZGVsLlxuICAgICAgICAgKlxuICAgICAgICAgKiBEZXBlbmRpbmcgb24gdGhlIGxhbmd1YWdlIGluIHdoaWNoIHlvdSBoYXZlIHdyaXR0ZW4geW91ciBtb2RlbCwgdGhlIG1ldGhvZCBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiBUaGUgYHBhcmFtc2AgYXJndW1lbnQgaXMgbm9ybWFsbHkgYW4gYXJyYXkgb2YgYXJndW1lbnRzIHRvIHRoZSBgb3BlcmF0aW9uYC4gSW4gdGhlIHNwZWNpYWwgY2FzZSB3aGVyZSBgb3BlcmF0aW9uYCBvbmx5IHRha2VzIG9uZSBhcmd1bWVudCwgeW91IGFyZSBub3QgcmVxdWlyZWQgdG8gcHV0IHRoYXQgYXJndW1lbnQgaW50byBhbiBhcnJheS5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IHlvdSBjYW4gY29tYmluZSB0aGUgYG9wZXJhdGlvbmAgYW5kIGBwYXJhbXNgIGFyZ3VtZW50cyBpbnRvIGEgc2luZ2xlIG9iamVjdCBpZiB5b3UgcHJlZmVyLCBhcyBpbiB0aGUgbGFzdCBleGFtcGxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJzb2x2ZVwiIHRha2VzIG5vIGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMuZG8oJ3NvbHZlJyk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgWydoZWxsbyddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJlY2hvXCIgdGFrZXMgb25lIGFyZ3VtZW50LCBhIHN0cmluZ1xuICAgICAgICAgKiAgICAgcnMuZG8oJ2VjaG8nLCAnaGVsbG8nKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJzdW1BcnJheVwiIHRha2VzIG9uZSBhcmd1bWVudCwgYW4gYXJyYXlcbiAgICAgICAgICogICAgIHJzLmRvKCdzdW1BcnJheScsIFtbNCwyLDFdXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiYWRkXCIgdGFrZXMgdHdvIGFyZ3VtZW50cywgYm90aCBpbnRlZ2Vyc1xuICAgICAgICAgKiAgICAgcnMuZG8oeyBuYW1lOidhZGQnLCBwYXJhbXM6WzIsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgb3BlcmF0aW9uYCBOYW1lIG9mIG1ldGhvZC5cbiAgICAgICAgICogQHBhcmFtIHtBcnJheX0gYHBhcmFtc2AgKE9wdGlvbmFsKSBBbnkgcGFyYW1ldGVycyB0aGUgb3BlcmF0aW9uIHRha2VzLCBwYXNzZWQgYXMgYW4gYXJyYXkuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXksIGFuZCBjYW4ganVzdCBwYXNzIGl0IGRpcmVjdGx5LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBkbzogZnVuY3Rpb24gKG9wZXJhdGlvbiwgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAvLyBjb25zb2xlLmxvZygnZG8nLCBvcGVyYXRpb24sIHBhcmFtcyk7XG4gICAgICAgICAgICB2YXIgb3BzQXJncztcbiAgICAgICAgICAgIHZhciBwb3N0T3B0aW9ucztcbiAgICAgICAgICAgIGlmIChvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3BzQXJncyA9IHBhcmFtcztcbiAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSkge1xuICAgICAgICAgICAgICAgICAgICBvcHNBcmdzID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgb3BzQXJncyA9IHBhcmFtcztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gcnV0aWwubm9ybWFsaXplT3BlcmF0aW9ucyhvcGVyYXRpb24sIG9wc0FyZ3MpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBwb3N0T3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHNldEZpbHRlck9yVGhyb3dFcnJvcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBwcm1zID0gKHJlc3VsdC5hcmdzWzBdLmxlbmd0aCAmJiAocmVzdWx0LmFyZ3NbMF0gIT09IG51bGwgJiYgcmVzdWx0LmFyZ3NbMF0gIT09IHVuZGVmaW5lZCkpID8gcmVzdWx0LmFyZ3NbMF0gOiBbXTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoeyBhcmd1bWVudHM6IHBybXMgfSwgJC5leHRlbmQodHJ1ZSwge30sIGh0dHBPcHRpb25zLCB7XG4gICAgICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMKCkgKyAnb3BlcmF0aW9ucy8nICsgcmVzdWx0Lm9wc1swXSArICcvJ1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbCwgc2VxdWVudGlhbGx5LlxuICAgICAgICAgKlxuICAgICAgICAgKiBEZXBlbmRpbmcgb24gdGhlIGxhbmd1YWdlIGluIHdoaWNoIHlvdSBoYXZlIHdyaXR0ZW4geW91ciBtb2RlbCwgdGhlIG1ldGhvZHMgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kcyBcImluaXRpYWxpemVcIiBhbmQgXCJzb2x2ZVwiIGRvIG5vdCB0YWtlIGFueSBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbJ2luaXRpYWxpemUnLCAnc29sdmUnXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kcyBcImluaXRcIiBhbmQgXCJyZXNldFwiIHRha2UgdHdvIGFyZ3VtZW50cyBlYWNoXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWyAgeyBuYW1lOiAnaW5pdCcsIHBhcmFtczogWzEsMl0gfSxcbiAgICAgICAgICogICAgICAgICAgICAgICAgICB7IG5hbWU6ICdyZXNldCcsIHBhcmFtczogWzIsM10gfV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImluaXRcIiB0YWtlcyB0d28gYXJndW1lbnRzLFxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcInJ1bm1vZGVsXCIgdGFrZXMgbm9uZVxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncnVubW9kZWwnLCBwYXJhbXM6IFtdIH1dKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtBcnJheX0gYG9wZXJhdGlvbnNgIElmIG5vbmUgb2YgdGhlIG1ldGhvZHMgdGFrZSBwYXJhbWV0ZXJzLCBwYXNzIGFuIGFycmF5IG9mIHRoZSBtZXRob2QgbmFtZXMgKHN0cmluZ3MpLiBJZiBhbnkgb2YgdGhlIG1ldGhvZHMgZG8gdGFrZSBwYXJhbWV0ZXJzLCBwYXNzIGFuIGFycmF5IG9mIG9iamVjdHMsIGVhY2ggb2Ygd2hpY2ggY29udGFpbnMgYSBtZXRob2QgbmFtZSBhbmQgaXRzIG93biAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNlcmlhbDogZnVuY3Rpb24gKG9wZXJhdGlvbnMsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIG9wUGFyYW1zID0gcnV0aWwubm9ybWFsaXplT3BlcmF0aW9ucyhvcGVyYXRpb25zLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wcyA9IG9wUGFyYW1zLm9wcztcbiAgICAgICAgICAgIHZhciBhcmdzID0gb3BQYXJhbXMuYXJncztcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBwb3N0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb1NpbmdsZU9wID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBvcCA9IG9wcy5zaGlmdCgpO1xuICAgICAgICAgICAgICAgIHZhciBhcmcgPSBhcmdzLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgICAgICBtZS5kbyhvcCwgYXJnLCB7XG4gICAgICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChvcHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2Vzcy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBlcnJvcjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVqZWN0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBkb1NpbmdsZU9wKCk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGwgc2V2ZXJhbCBtZXRob2RzIGZyb20gdGhlIG1vZGVsLCBleGVjdXRpbmcgdGhlbSBpbiBwYXJhbGxlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2RzIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kcyBcInNvbHZlXCIgYW5kIFwicmVzZXRcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5wYXJhbGxlbChbJ3NvbHZlJywgJ3Jlc2V0J10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJhZGRcIiBhbmQgXCJzdWJ0cmFjdFwiIHRha2UgdHdvIGFyZ3VtZW50cyBlYWNoXG4gICAgICAgICAqICAgICBycy5wYXJhbGxlbChbIHsgbmFtZTogJ2FkZCcsIHBhcmFtczogWzEsMl0gfSxcbiAgICAgICAgICogICAgICAgICAgICAgICAgICAgeyBuYW1lOiAnc3VidHJhY3QnLCBwYXJhbXM6WzIsM10gfV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJhZGRcIiBhbmQgXCJzdWJ0cmFjdFwiIHRha2UgdHdvIGFyZ3VtZW50cyBlYWNoXG4gICAgICAgICAqICAgICBycy5wYXJhbGxlbCh7IGFkZDogWzEsMl0sIHN1YnRyYWN0OiBbMiw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R9IGBvcGVyYXRpb25zYCBJZiBub25lIG9mIHRoZSBtZXRob2RzIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgbWV0aG9kIG5hbWVzIChhcyBzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBtZXRob2RzIGRvIHRha2UgcGFyYW1ldGVycywgeW91IGhhdmUgdHdvIG9wdGlvbnMuIFlvdSBjYW4gcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGEgbWV0aG9kIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLiBBbHRlcm5hdGl2ZWx5LCB5b3UgY2FuIHBhc3MgYSBzaW5nbGUgb2JqZWN0IHdpdGggdGhlIG1ldGhvZCBuYW1lIGFuZCBhIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy5cbiAgICAgICAgICogQHBhcmFtIHsqfSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHBhc3MgdG8gb3BlcmF0aW9ucy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcGFyYWxsZWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICAgICAgdmFyIG9wUGFyYW1zID0gcnV0aWwubm9ybWFsaXplT3BlcmF0aW9ucyhvcGVyYXRpb25zLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wcyA9IG9wUGFyYW1zLm9wcztcbiAgICAgICAgICAgIHZhciBhcmdzID0gb3BQYXJhbXMuYXJncztcbiAgICAgICAgICAgIHZhciBwb3N0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBxdWV1ZSAgPSBbXTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpPCBvcHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBxdWV1ZS5wdXNoKFxuICAgICAgICAgICAgICAgICAgICB0aGlzLmRvKG9wc1tpXSwgYXJnc1tpXSlcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJC53aGVuLmFwcGx5KHRoaXMsIHF1ZXVlKVxuICAgICAgICAgICAgICAgIC5kb25lKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5zdWNjZXNzLmFwcGx5KHRoaXMuYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVqZWN0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLmVycm9yLmFwcGx5KHRoaXMuYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljU3luY0FQSSA9IHtcbiAgICAgICAgZ2V0Q3VycmVudENvbmZpZzogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zO1xuICAgICAgICB9LFxuICAgICAgICAvKipcbiAgICAgICAgICAqIFJldHVybnMgYSBWYXJpYWJsZXMgU2VydmljZSBpbnN0YW5jZS4gVXNlIHRoZSB2YXJpYWJsZXMgaW5zdGFuY2UgdG8gbG9hZCwgc2F2ZSwgYW5kIHF1ZXJ5IGZvciBzcGVjaWZpYyBtb2RlbCB2YXJpYWJsZXMuIFNlZSB0aGUgW1ZhcmlhYmxlIEFQSSBTZXJ2aWNlXSguLi92YXJpYWJsZXMtYXBpLXNlcnZpY2UvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi5cbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgICpcbiAgICAgICAgICAqICAgICAgdmFyIHZzID0gcnMudmFyaWFibGVzKCk7XG4gICAgICAgICAgKiAgICAgIHZzLnNhdmUoeyBzYW1wbGVfaW50OiA0IH0pO1xuICAgICAgICAgICpcbiAgICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGNvbmZpZ2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICAqL1xuICAgICAgICB2YXJpYWJsZXM6IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAgICAgICAgIHZhciB2cyA9IG5ldyBWYXJpYWJsZXNTZXJ2aWNlKCQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgY29uZmlnLCB7XG4gICAgICAgICAgICAgICAgcnVuU2VydmljZTogdGhpc1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgICAgcmV0dXJuIHZzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FzeW5jQVBJKTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNTeW5jQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG4vKipcbiAqICMjU3RhdGUgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgU3RhdGUgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byByZXBsYXkgb3IgY2xvbmUgcnVucy4gSXQgYnJpbmdzIGV4aXN0aW5nLCBwZXJzaXN0ZWQgcnVuIGRhdGEgZnJvbSB0aGUgZGF0YWJhc2UgYmFjayBpbnRvIG1lbW9yeSwgdXNpbmcgdGhlIHNhbWUgcnVuIGlkIChgcmVwbGF5YCkgb3IgYSBuZXcgcnVuIGlkIChgY2xvbmVgKS4gUnVucyBtdXN0IGJlIGluIG1lbW9yeSBpbiBvcmRlciBmb3IgeW91IHRvIHVwZGF0ZSB2YXJpYWJsZXMgb3IgY2FsbCBvcGVyYXRpb25zIG9uIHRoZW0uXG4gKlxuICogU3BlY2lmaWNhbGx5LCB0aGUgU3RhdGUgQVBJIEFkYXB0ZXIgd29ya3MgYnkgXCJyZS1ydW5uaW5nXCIgdGhlIHJ1biAodXNlciBpbnRlcmFjdGlvbnMpIGZyb20gdGhlIGNyZWF0aW9uIG9mIHRoZSBydW4gdXAgdG8gdGhlIHRpbWUgaXQgd2FzIGxhc3QgcGVyc2lzdGVkIGluIHRoZSBkYXRhYmFzZS4gVGhpcyBwcm9jZXNzIHVzZXMgdGhlIGN1cnJlbnQgdmVyc2lvbiBvZiB0aGUgcnVuJ3MgbW9kZWwuIFRoZXJlZm9yZSwgaWYgdGhlIG1vZGVsIGhhcyBjaGFuZ2VkIHNpbmNlIHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQsIHRoZSByZXRyaWV2ZWQgcnVuIHdpbGwgdXNlIHRoZSBuZXcgbW9kZWwg4oCUIGFuZCBtYXkgZW5kIHVwIGhhdmluZyBkaWZmZXJlbnQgdmFsdWVzIG9yIGJlaGF2aW9yIGFzIGEgcmVzdWx0LiBVc2Ugd2l0aCBjYXJlIVxuICpcbiAqIFRvIHVzZSB0aGUgU3RhdGUgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHM6XG4gKlxuICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gKiAgICAgIHNhLnJlcGxheSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnfSk7XG4gKlxuICogVGhlIGNvbnN0cnVjdG9yIHRha2VzIGFuIG9wdGlvbmFsIGBvcHRpb25zYCBwYXJhbWV0ZXIgaW4gd2hpY2ggeW91IGNhbiBzcGVjaWZ5IHRoZSBgYWNjb3VudGAgYW5kIGBwcm9qZWN0YCBpZiB0aGV5IGFyZSBub3QgYWxyZWFkeSBhdmFpbGFibGUgaW4gdGhlIGN1cnJlbnQgY29udGV4dC5cbiAqXG4gKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGFwaUVuZHBvaW50ID0gJ21vZGVsL3N0YXRlJztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG5cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuICAgIHZhciBwYXJzZVJ1bklkT3JFcnJvciA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChwYXJhbXMpICYmIHBhcmFtcy5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHBhcmFtcy5ydW5JZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHBhc3MgaW4gYSBydW4gaWQnKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgKiBSZXBsYXkgYSBydW4uIEFmdGVyIHRoaXMgY2FsbCwgdGhlIHJ1biwgd2l0aCBpdHMgb3JpZ2luYWwgcnVuIGlkLCBpcyBub3cgYXZhaWxhYmxlIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoSXQgY29udGludWVzIHRvIGJlIHBlcnNpc3RlZCBpbnRvIHRoZSBFcGljZW50ZXIgZGF0YWJhc2UgYXQgcmVndWxhciBpbnRlcnZhbHMuKVxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciBzYSA9IG5ldyBGLnNlcnZpY2UuU3RhdGUoKTtcbiAgICAgICAgKiAgICAgIHNhLnJlcGxheSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyBvYmplY3QuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMucnVuSWRgIFRoZSBpZCBvZiB0aGUgcnVuIHRvIGJyaW5nIGJhY2sgdG8gbWVtb3J5LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnN0b3BCZWZvcmVgIChPcHRpb25hbCkgVGhlIHJ1biBpcyBhZHZhbmNlZCBvbmx5IHVwIHRvIHRoZSBmaXJzdCBvY2N1cnJlbmNlIG9mIHRoaXMgbWV0aG9kLlxuICAgICAgICAqIEBwYXJhbSB7YXJyYXl9IGBwYXJhbXMuZXhjbHVkZWAgKE9wdGlvbmFsKSBBcnJheSBvZiBtZXRob2RzIHRvIGV4Y2x1ZGUgd2hlbiBhZHZhbmNpbmcgdGhlIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIHJlcGxheTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHJ1bklkID0gcGFyc2VSdW5JZE9yRXJyb3IocGFyYW1zKTtcblxuICAgICAgICAgICAgdmFyIHJlcGxheU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBydW5JZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBwYXJhbXMgPSAkLmV4dGVuZCh0cnVlLCB7IGFjdGlvbjogJ3JlcGxheScgfSwgX3BpY2socGFyYW1zLCBbJ3N0b3BCZWZvcmUnLCAnZXhjbHVkZSddKSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCByZXBsYXlPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBDbG9uZSBhIGdpdmVuIHJ1biBhbmQgcmV0dXJuIGEgbmV3IHJ1biBpbiB0aGUgc2FtZSBzdGF0ZSBhcyB0aGUgZ2l2ZW4gcnVuLlxuICAgICAgICAqXG4gICAgICAgICogVGhlIG5ldyBydW4gaWQgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gVGhlIG5ldyBydW4gaW5jbHVkZXMgYSBjb3B5IG9mIGFsbCBvZiB0aGUgZGF0YSBmcm9tIHRoZSBvcmlnaW5hbCBydW4sIEVYQ0VQVDpcbiAgICAgICAgKlxuICAgICAgICAqICogVGhlIGBzYXZlZGAgZmllbGQgaW4gdGhlIG5ldyBydW4gcmVjb3JkIGlzIG5vdCBjb3BpZWQgZnJvbSB0aGUgb3JpZ2luYWwgcnVuIHJlY29yZC4gSXQgZGVmYXVsdHMgdG8gYGZhbHNlYC5cbiAgICAgICAgKiAqIFRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAgYnV0IG1heSBjaGFuZ2UgdG8gYHRydWVgIGFzIHRoZSBuZXcgcnVuIGlzIGFkdmFuY2VkLiBGb3IgZXhhbXBsZSwgaWYgdGhlcmUgaGFzIGJlZW4gYSBjYWxsIHRvIHRoZSBgc3RlcGAgZnVuY3Rpb24gKGZvciBWZW5zaW0gbW9kZWxzKSwgdGhlIGBpbml0aWFsaXplZGAgZmllbGQgaXMgc2V0IHRvIGB0cnVlYC5cbiAgICAgICAgKiAqIFRoZSBgY3JlYXRlZGAgZmllbGQgaW4gdGhlIG5ldyBydW4gcmVjb3JkIGlzIHRoZSBkYXRlIGFuZCB0aW1lIGF0IHdoaWNoIHRoZSBjbG9uZSB3YXMgY3JlYXRlZCAobm90IHRoZSB0aW1lIHRoYXQgdGhlIG9yaWdpbmFsIHJ1biB3YXMgY3JlYXRlZC4pXG4gICAgICAgICpcbiAgICAgICAgKiBUaGUgb3JpZ2luYWwgcnVuIHJlbWFpbnMgb25seSBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciBzYSA9IG5ldyBGLnNlcnZpY2UuU3RhdGUoKTtcbiAgICAgICAgKiAgICAgIHNhLmNsb25lKHtydW5JZDogJzE4NDJiYjVjLTgzYWQtNGJhOC1hOTU1LWJkMTNjYzJmZGI0ZicsIHN0b3BCZWZvcmU6ICdjYWxjdWxhdGVTY29yZScsIGV4Y2x1ZGU6IFsnaW50ZXJpbUNhbGN1bGF0aW9uJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyBvYmplY3QuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMucnVuSWRgIFRoZSBpZCBvZiB0aGUgcnVuIHRvIGNsb25lIGZyb20gbWVtb3J5LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnN0b3BCZWZvcmVgIChPcHRpb25hbCkgVGhlIG5ld2x5IGNsb25lZCBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBgcGFyYW1zLmV4Y2x1ZGVgIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBuZXdseSBjbG9uZWQgcnVuLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgY2xvbmU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdjbG9uZScgfSwgX3BpY2socGFyYW1zLCBbJ3N0b3BCZWZvcmUnLCAnZXhjbHVkZSddKSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCByZXBsYXlPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVwaVZlcnNpb24gPSByZXF1aXJlKCcuLi9hcGktdmVyc2lvbi5qc29uJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vVE9ETzogdXJsdXRpbHMgdG8gZ2V0IGhvc3QsIHNpbmNlIG5vIHdpbmRvdyBvbiBub2RlXG5cbiAgICB2YXIgQVBJX1BST1RPQ09MID0gJ2h0dHBzJztcbiAgICB2YXIgSE9TVF9BUElfTUFQUElORyA9IHtcbiAgICAgICAgJ2ZvcmlvLmNvbSc6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgJ2ZvcmlvZGV2LmNvbSc6ICdhcGkuZXBpY2VudGVyLmZvcmlvZGV2LmNvbSdcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0V4cG9ydHMgPSB7XG4gICAgICAgIHByb3RvY29sOiBBUElfUFJPVE9DT0wsXG5cbiAgICAgICAgYXBpOiAnJyxcblxuICAgICAgICBob3N0OiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGhvc3QgPSB3aW5kb3cubG9jYXRpb24uaG9zdDtcbiAgICAgICAgICAgIGlmICghaG9zdCB8fCBob3N0LmluZGV4T2YoJ2xvY2FsJykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgaG9zdCA9ICdmb3Jpby5jb20nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIChIT1NUX0FQSV9NQVBQSU5HW2hvc3RdKSA/IEhPU1RfQVBJX01BUFBJTkdbaG9zdF0gOiAnYXBpLicgKyBob3N0O1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFwcFBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG5cbiAgICAgICAgICAgIHJldHVybiBwYXRoICYmIHBhdGhbMV0gfHwgJyc7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgYWNjb3VudFBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYWNjbnQgPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIGlmIChwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnKSB7XG4gICAgICAgICAgICAgICAgYWNjbnQgPSBwYXRoWzJdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFjY250O1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIHByb2plY3RQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHByaiA9ICcnO1xuICAgICAgICAgICAgdmFyIHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuICAgICAgICAgICAgaWYgKHBhdGggJiYgcGF0aFsxXSA9PT0gJ2FwcCcpIHtcbiAgICAgICAgICAgICAgICBwcmogPSBwYXRoWzNdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHByajtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICB2ZXJzaW9uUGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciB2ZXJzaW9uID0gZXBpVmVyc2lvbi52ZXJzaW9uID8gZXBpVmVyc2lvbi52ZXJzaW9uICsgJy8nIDogJyc7XG4gICAgICAgICAgICByZXR1cm4gdmVyc2lvbjtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBpc0xvY2FsaG9zdDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGhvc3QgPSB3aW5kb3cubG9jYXRpb24uaG9zdDtcbiAgICAgICAgICAgIHJldHVybiAoIWhvc3QgfHwgaG9zdC5pbmRleE9mKCdsb2NhbCcpICE9PSAtMSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgZ2V0QVBJUGF0aDogZnVuY3Rpb24gKGFwaSkge1xuICAgICAgICAgICAgdmFyIFBST0pFQ1RfQVBJUyA9IFsncnVuJywgJ2RhdGEnLCAnZmlsZSddO1xuXG4gICAgICAgICAgICB2YXIgYXBpUGF0aCA9IHRoaXMucHJvdG9jb2wgKyAnOi8vJyArIHRoaXMuaG9zdCArICcvJyArIHRoaXMudmVyc2lvblBhdGggKyBhcGkgKyAnLyc7XG5cbiAgICAgICAgICAgIGlmICgkLmluQXJyYXkoYXBpLCBQUk9KRUNUX0FQSVMpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGFwaVBhdGggKz0gdGhpcy5hY2NvdW50UGF0aCArICcvJyArIHRoaXMucHJvamVjdFBhdGggICsgJy8nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFwaVBhdGg7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQocHVibGljRXhwb3J0cywgY29uZmlnKTtcbiAgICByZXR1cm4gcHVibGljRXhwb3J0cztcbn07XG4iLCIndXNlIHN0cmljdCc7XG4vKipcbiogIyNVc2VyIEFQSSBBZGFwdGVyXG4qXG4qIFRoZSBVc2VyIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gcmV0cmlldmUgZGV0YWlscyBhYm91dCBlbmQgdXNlcnMgaW4geW91ciB0ZWFtIChhY2NvdW50KS4gSXQgaXMgYmFzZWQgb24gdGhlIHF1ZXJ5aW5nIGNhcGFiaWxpdGllcyBvZiB0aGUgdW5kZXJseWluZyBSRVNUZnVsIFtVc2VyIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL3VzZXJfbWFuYWdlbWVudC91c2VyLykuXG4qXG4qIFRvIHVzZSB0aGUgVXNlciBBUEkgQWRhcHRlciwgaW5zdGFudGlhdGUgaXQgYW5kIHRoZW4gY2FsbCBpdHMgbWV0aG9kcy5cbipcbiogICAgICAgdmFyIHVhID0gbmV3IEYuc2VydmljZS5Vc2VyKHtcbiogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiogICAgICAgfSk7XG4qICAgICAgIHVhLmdldEJ5SWQoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpO1xuKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4qICAgICAgIHVhLmdldCh7IGlkOiBbJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycsXG4qICAgICAgICAgICAgICAgICAgICc0ZWE3NTYzMS00YzhkLTQ4NzItOWQ4MC1iNDYwMDE0NjQ3OGUnXSB9KTtcbipcbiogVGhlIGNvbnN0cnVjdG9yIHRha2VzIGFuIG9wdGlvbmFsIGBvcHRpb25zYCBwYXJhbWV0ZXIgaW4gd2hpY2ggeW91IGNhbiBzcGVjaWZ5IHRoZSBgYWNjb3VudGAgYW5kIGB0b2tlbmAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4qL1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY2VzcyB0b2tlbiB0byB1c2Ugd2hlbiBzZWFyY2hpbmcgZm9yIGVuZCB1c2Vycy4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICB0b2tlbjogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG5cbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCd1c2VyJylcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBwYXJ0aWN1bGFyIGVuZCB1c2VycyBpbiB5b3VyIHRlYW0sIGJhc2VkIG9uIHVzZXIgbmFtZSBvciB1c2VyIGlkLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqICAgICAgIHVhLmdldCh7IHVzZXJOYW1lOiAnanNtaXRoJyB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICc0ZWE3NTYzMS00YzhkLTQ4NzItOWQ4MC1iNDYwMDE0NjQ3OGUnXSB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBmaWx0ZXJgIE9iamVjdCB3aXRoIGZpZWxkIGB1c2VyTmFtZWAgYW5kIHZhbHVlIG9mIHRoZSB1c2VybmFtZS4gQWx0ZXJuYXRpdmVseSwgb2JqZWN0IHdpdGggZmllbGQgYGlkYCBhbmQgdmFsdWUgb2YgYW4gYXJyYXkgb2YgdXNlciBpZHMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuXG4gICAgICAgIGdldDogZnVuY3Rpb24gKGZpbHRlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBmaWx0ZXIgPSBmaWx0ZXIgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9uc1xuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIHRvUUZpbHRlciA9IGZ1bmN0aW9uIChmaWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzID0ge307XG5cbiAgICAgICAgICAgICAgICAvLyBBUEkgb25seSBzdXBwb3J0cyBmaWx0ZXJpbmcgYnkgdXNlcm5hbWUgZm9yIG5vd1xuICAgICAgICAgICAgICAgIGlmIChmaWx0ZXIudXNlck5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzLnEgPSBmaWx0ZXIudXNlck5hbWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciB0b0lkRmlsdGVycyA9IGZ1bmN0aW9uIChpZCkge1xuICAgICAgICAgICAgICAgIGlmICghaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlkID0gJC5pc0FycmF5KGlkKSA/IGlkIDogW2lkXTtcbiAgICAgICAgICAgICAgICByZXR1cm4gJ2lkPScgKyBpZC5qb2luKCcmaWQ9Jyk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0RmlsdGVycyA9IFtcbiAgICAgICAgICAgICAgICAnYWNjb3VudD0nICsgZ2V0T3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgIHRvSWRGaWx0ZXJzKGZpbHRlci5pZCksXG4gICAgICAgICAgICAgICAgcXV0aWwudG9RdWVyeUZvcm1hdCh0b1FGaWx0ZXIoZmlsdGVyKSlcbiAgICAgICAgICAgIF0uam9pbignJicpO1xuXG4gICAgICAgICAgICAvLyBzcGVjaWFsIGNhc2UgZm9yIHF1ZXJpZXMgd2l0aCBsYXJnZSBudW1iZXIgb2YgaWRzXG4gICAgICAgICAgICAvLyBtYWtlIGl0IGFzIGEgcG9zdCB3aXRoIEdFVCBzZW1hbnRpY3NcbiAgICAgICAgICAgIHZhciB0aHJlc2hvbGQgPSAzMDtcbiAgICAgICAgICAgIGlmIChmaWx0ZXIuaWQgJiYgJC5pc0FycmF5KGZpbHRlci5pZCkgJiYgZmlsdGVyLmlkLmxlbmd0aCA+PSB0aHJlc2hvbGQpIHtcbiAgICAgICAgICAgICAgICBnZXRPcHRpb25zLnVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCd1c2VyJykgKyAnP19tZXRob2Q9R0VUJztcbiAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgaWQ6IGZpbHRlci5pZCB9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldEZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgYSBzaW5nbGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIGlkLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqICAgICAgIHVhLmdldEJ5SWQoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJJZGAgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlciBpbiB5b3VyIHRlYW0uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuXG4gICAgICAgIGdldEJ5SWQ6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBwdWJsaWNBUEkuZ2V0KHsgaWQ6IHVzZXJJZCB9LCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcblxuXG5cblxuIiwiLyoqXG4gKlxuICogIyNWYXJpYWJsZXMgQVBJIFNlcnZpY2VcbiAqXG4gKiBVc2VkIGluIGNvbmp1bmN0aW9uIHdpdGggdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pIHRvIHJlYWQsIHdyaXRlLCBhbmQgc2VhcmNoIGZvciBzcGVjaWZpYyBtb2RlbCB2YXJpYWJsZXMuXG4gKlxuICogICAgIHZhciBybSA9IG5ldyBGLm1hbmFnZXIuUnVuTWFuYWdlcih7XG4gKiAgICAgICAgICAgcnVuOiB7XG4gKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgICAgICAgbW9kZWw6ICdzdXBwbHktY2hhaW4tbW9kZWwuamwnXG4gKiAgICAgICAgICAgfVxuICogICAgICB9KTtcbiAqICAgICBybS5nZXRSdW4oKVxuICogICAgICAgLnRoZW4oZnVuY3Rpb24oKSB7XG4gKiAgICAgICAgICB2YXIgdnMgPSBybS5ydW4udmFyaWFibGVzKCk7XG4gKiAgICAgICAgICB2cy5zYXZlKHtzYW1wbGVfaW50OiA0fSk7XG4gKiAgICAgICAgfSk7XG4gKlxuICovXG5cblxuICd1c2Ugc3RyaWN0JztcblxuIHZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbiB2YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBydW5zIG9iamVjdCB0byB3aGljaCB0aGUgdmFyaWFibGUgZmlsdGVycyBhcHBseS4gRGVmYXVsdHMgdG8gbnVsbC5cbiAgICAgICAgICogQHR5cGUge3J1blNlcnZpY2V9XG4gICAgICAgICAqL1xuICAgICAgICBydW5TZXJ2aWNlOiBudWxsXG4gICAgfTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG5cbiAgICB2YXIgZ2V0VVJMID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuZ2V0RmlsdGVyVVJMKCkgKyAndmFyaWFibGVzLyc7XG4gICAgfTtcblxuICAgIHZhciBhZGRBdXRvUmVzdG9yZUhlYWRlciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucy5ydW5TZXJ2aWNlLnVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihvcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0ge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH07XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIGh0dHBPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuICAgIGh0dHAuc3BsaXRHZXQgPSBydXRpbC5zcGxpdEdldEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHZhbHVlcyBmb3IgYSB2YXJpYWJsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICB2cy5sb2FkKCdzYW1wbGVfaW50JylcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKXtcbiAgICAgICAgICogICAgICAgICAgICAgIC8vIHZhbCBjb250YWlucyB0aGUgdmFsdWUgb2Ygc2FtcGxlX2ludFxuICAgICAgICAgKiAgICAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGB2YXJpYWJsZWAgTmFtZSBvZiB2YXJpYWJsZSB0byBsb2FkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAodmFyaWFibGUsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSBhZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsICQuZXh0ZW5kKHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogZ2V0VVJMKCkgKyB2YXJpYWJsZSArICcvJ1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZXR1cm5zIHBhcnRpY3VsYXIgdmFyaWFibGVzLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHF1ZXJ5YCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoWydwcmljZScsICdzYWxlcyddKVxuICAgICAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbih2YWwpIHtcbiAgICAgICAgICogICAgICAgICAgICAgIC8vIHZhbCBpcyBhbiBvYmplY3Qgd2l0aCB0aGUgdmFsdWVzIG9mIHRoZSByZXF1ZXN0ZWQgdmFyaWFibGVzOiB2YWwucHJpY2UsIHZhbC5zYWxlc1xuICAgICAgICAgKiAgICAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICB2cy5xdWVyeSh7IGluY2x1ZGU6WydwcmljZScsICdzYWxlcyddIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdHxBcnJheX0gYHF1ZXJ5YCBUaGUgbmFtZXMgb2YgdGhlIHZhcmlhYmxlcyByZXF1ZXN0ZWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICpcbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXVlcnksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAvL1F1ZXJ5IGFuZCBvdXRwdXRNb2RpZmllciBhcmUgYm90aCBxdWVyeXN0cmluZ3MgaW4gdGhlIHVybDsgb25seSBjYWxsaW5nIHRoZW0gb3V0IHNlcGFyYXRlbHkgaGVyZSB0byBiZSBjb25zaXN0ZW50IHdpdGggdGhlIG90aGVyIGNhbGxzXG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSBhZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIGlmICgkLmlzQXJyYXkocXVlcnkpKSB7XG4gICAgICAgICAgICAgICAgcXVlcnkgPSB7IGluY2x1ZGU6IHF1ZXJ5IH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAkLmV4dGVuZChxdWVyeSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuc3BsaXRHZXQocXVlcnksIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSB2YWx1ZXMgdG8gbW9kZWwgdmFyaWFibGVzLiBPdmVyd3JpdGVzIGV4aXN0aW5nIHZhbHVlcy4gTm90ZSB0aGF0IHlvdSBjYW4gb25seSB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlmIHRoZSBydW4gaXMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIChBbiBhbHRlcm5hdGUgd2F5IHRvIHVwZGF0ZSBtb2RlbCB2YXJpYWJsZXMgaXMgdG8gY2FsbCBhIG1ldGhvZCBmcm9tIHRoZSBtb2RlbCBhbmQgbWFrZSBzdXJlIHRoYXQgdGhlIG1ldGhvZCBwZXJzaXN0cyB0aGUgdmFyaWFibGVzLiBTZWUgYGRvYCwgYHNlcmlhbGAsIGFuZCBgcGFyYWxsZWxgIGluIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBmb3IgY2FsbGluZyBtZXRob2RzIGZyb20gdGhlIG1vZGVsLilcbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICB2cy5zYXZlKCdwcmljZScsIDQpO1xuICAgICAgICAgKiAgICAgIHZzLnNhdmUoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdHxTdHJpbmd9IGB2YXJpYWJsZWAgQW4gb2JqZWN0IGNvbXBvc2VkIG9mIHRoZSBtb2RlbCB2YXJpYWJsZXMgYW5kIHRoZSB2YWx1ZXMgdG8gc2F2ZS4gQWx0ZXJuYXRpdmVseSwgYSBzdHJpbmcgd2l0aCB0aGUgbmFtZSBvZiB0aGUgdmFyaWFibGUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgdmFsYCAoT3B0aW9uYWwpIElmIHBhc3NpbmcgYSBzdHJpbmcgZm9yIGB2YXJpYWJsZWAsIHVzZSB0aGlzIGFyZ3VtZW50IGZvciB0aGUgdmFsdWUgdG8gc2F2ZS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgYXR0cnMgPSB2YXJpYWJsZTtcbiAgICAgICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gTm90IEF2YWlsYWJsZSB1bnRpbCB1bmRlcmx5aW5nIEFQSSBzdXBwb3J0cyBQVVQuIE90aGVyd2lzZSBzYXZlIHdvdWxkIGJlIFBVVCBhbmQgbWVyZ2Ugd291bGQgYmUgUEFUQ0hcbiAgICAgICAgLy8gKlxuICAgICAgICAvLyAgKiBTYXZlIHZhbHVlcyB0byB0aGUgYXBpLiBNZXJnZXMgYXJyYXlzLCBidXQgb3RoZXJ3aXNlIHNhbWUgYXMgc2F2ZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdHxTdHJpbmd9IHZhcmlhYmxlIE9iamVjdCB3aXRoIGF0dHJpYnV0ZXMsIG9yIHN0cmluZyBrZXlcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R9IHZhbCBPcHRpb25hbCBpZiBwcmV2IHBhcmFtZXRlciB3YXMgYSBzdHJpbmcsIHNldCB2YWx1ZSBoZXJlXG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBleGFtcGxlXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSh7IHByaWNlOiA0LCBxdWFudGl0eTogNSwgcHJvZHVjdHM6IFsyLDMsNF0gfSlcbiAgICAgICAgLy8gICogICAgIHZzLm1lcmdlKCdwcmljZScsIDQpO1xuXG4gICAgICAgIC8vIG1lcmdlOiBmdW5jdGlvbiAodmFyaWFibGUsIHZhbCwgb3B0aW9ucykge1xuICAgICAgICAvLyAgICAgdmFyIGF0dHJzO1xuICAgICAgICAvLyAgICAgaWYgKHR5cGVvZiB2YXJpYWJsZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgLy8gICAgICAgYXR0cnMgPSB2YXJpYWJsZTtcbiAgICAgICAgLy8gICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgLy8gICAgIH0gZWxzZSB7XG4gICAgICAgIC8vICAgICAgIChhdHRycyA9IHt9KVt2YXJpYWJsZV0gPSB2YWw7XG4gICAgICAgIC8vICAgICB9XG4gICAgICAgIC8vICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIC8vICAgICByZXR1cm4gaHR0cC5wYXRjaC5jYWxsKHRoaXMsIGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIC8vIH1cbiAgICB9O1xuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiAjI1dvcmxkIEFQSSBBZGFwdGVyXG4gKlxuICogQSBbcnVuXSguLi8uLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgZW5kIHVzZXIgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwgLS0gaW5jbHVkaW5nIHNldHRpbmcgdmFyaWFibGVzLCBtYWtpbmcgZGVjaXNpb25zLCBhbmQgY2FsbGluZyBvcGVyYXRpb25zLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLiBPbmx5IFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSkgY2FuIGJlIG11bHRpcGxheWVyLlxuICpcbiAqIFRoZSBXb3JsZCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgbWFuaXB1bGF0ZSBtdWx0aXBsYXllciB3b3JsZHMgd2l0aGluIHlvdXIgRXBpY2VudGVyIHByb2plY3QuIFlvdSBjYW4gdXNlIHRoaXMgdG8gYWRkIGFuZCByZW1vdmUgZW5kIHVzZXJzIGZyb20gdGhlIHdvcmxkLCBhbmQgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCByZW1vdmUgdGhlaXIgcnVucy4gQmVjYXVzZSBvZiB0aGlzLCB0eXBpY2FsbHkgdGhlIFdvcmxkIEFkYXB0ZXIgaXMgdXNlZCBmb3IgZmFjaWxpdGF0b3IgcGFnZXMgaW4geW91ciBwcm9qZWN0LiAoVGhlIHJlbGF0ZWQgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIvKSBwcm92aWRlcyBhbiBlYXN5IHdheSB0byBhY2Nlc3MgcnVucyBhbmQgd29ybGRzIGZvciBwYXJ0aWN1bGFyIGVuZCB1c2Vycywgc28gaXMgdHlwaWNhbGx5IHVzZWQgaW4gcGFnZXMgdGhhdCBlbmQgdXNlcnMgd2lsbCBpbnRlcmFjdCB3aXRoLilcbiAqXG4gKiBBcyB3aXRoIGFsbCB0aGUgb3RoZXIgW0FQSSBBZGFwdGVyc10oLi4vLi4vKSwgYWxsIG1ldGhvZHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFdvcmxkIEFQSSBTZXJ2aWNlIGRlZmF1bHRzLlxuICpcbiAqIFRvIHVzZSB0aGUgV29ybGQgQWRhcHRlciwgaW5zdGFudGlhdGUgaXQgYW5kIHRoZW4gYWNjZXNzIHRoZSBtZXRob2RzIHByb3ZpZGVkLiBJbnN0YW50aWF0aW5nIHJlcXVpcmVzIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBpbiB0aGUgRXBpY2VudGVyIHVzZXIgaW50ZXJmYWNlKSwgcHJvamVjdCBpZCAoKipQcm9qZWN0IElEKiopLCBhbmQgZ3JvdXAgKCoqR3JvdXAgTmFtZSoqKS5cbiAqXG4gKiAgICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAqICAgICAgIHdhLmNyZWF0ZSgpXG4gKiAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICogICAgICAgICAgICAgIC8vIGNhbGwgbWV0aG9kcywgZS5nLiB3YS5hZGRVc2VycygpXG4gKiAgICAgICAgICB9KTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbi8vIHZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xuXG52YXIgYXBpQmFzZSA9ICdtdWx0aXBsYXllci8nO1xudmFyIGFzc2lnbm1lbnRFbmRwb2ludCA9IGFwaUJhc2UgKyAnYXNzaWduJztcbnZhciBhcGlFbmRwb2ludCA9IGFwaUJhc2UgKyAnd29ybGQnO1xudmFyIHByb2plY3RFbmRwb2ludCA9IGFwaUJhc2UgKyAncHJvamVjdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIHByb2plY3RzIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgcHJvamVjdDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKS4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICBncm91cDogdW5kZWZpbmVkLFxuXG4gICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBtb2RlbCBmaWxlIHRvIHVzZSB0byBjcmVhdGUgcnVucyBpbiB0aGlzIHdvcmxkLiBEZWZhdWx0cyB0byB1bmRlZmluZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBtb2RlbDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgd29ybGQuIEN1cnJlbnRseSBvbmx5IHN1cHBvcnRzIHdvcmxkLWlkcyBhcyBmaWx0ZXJzLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlclxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgaWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge30sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGxlZCB3aGVuIHRoZSBjYWxsIGNvbXBsZXRlcyBzdWNjZXNzZnVsbHkuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBzdWNjZXNzOiAkLm5vb3AsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGxlZCB3aGVuIHRoZSBjYWxsIGZhaWxzLiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgZXJyb3I6ICQubm9vcFxuICAgIH07XG5cbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmlkKSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmlkO1xuICAgIH1cblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB3b3JsZCBpZCBzcGVjaWZpZWQgdG8gYXBwbHkgb3BlcmF0aW9ucyBhZ2FpbnN0LiBUaGlzIGNvdWxkIGhhcHBlbiBpZiB0aGUgdXNlciBpcyBub3QgYXNzaWduZWQgdG8gYSB3b3JsZCBhbmQgaXMgdHJ5aW5nIHRvIHdvcmsgd2l0aCBydW5zIGZyb20gdGhhdCB3b3JsZC4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmICghb3B0aW9ucy5tb2RlbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBtb2RlbCBzcGVjaWZpZWQgdG8gZ2V0IHRoZSBjdXJyZW50IHJ1bicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBXb3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFVzaW5nIHRoaXMgbWV0aG9kIGlzIHJhcmUuIEl0IGlzIG1vcmUgY29tbW9uIHRvIGNyZWF0ZSB3b3JsZHMgYXV0b21hdGljYWxseSB3aGlsZSB5b3UgYGF1dG9Bc3NpZ24oKWAgZW5kIHVzZXJzIHRvIHdvcmxkcy4gKEluIHRoaXMgY2FzZSwgY29uZmlndXJhdGlvbiBkYXRhIGZvciB0aGUgd29ybGQsIHN1Y2ggYXMgdGhlIHJvbGVzLCBhcmUgcmVhZCBmcm9tIHRoZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb24gaW5mb3JtYXRpb24sIGZvciBleGFtcGxlIGJ5IGBnZXRQcm9qZWN0U2V0dGluZ3MoKWAuKVxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKHtcbiAgICAgICAgKiAgICAgICAgICAgcm9sZXM6IFsnVlAgTWFya2V0aW5nJywgJ1ZQIFNhbGVzJywgJ1ZQIEVuZ2luZWVyaW5nJ11cbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIGNyZWF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZ3JvdXBgIChPcHRpb25hbCkgVGhlICoqR3JvdXAgTmFtZSoqIHRvIGNyZWF0ZSB0aGlzIHdvcmxkIHVuZGVyLiBPbmx5IGVuZCB1c2VycyBpbiB0aGlzIGdyb3VwIGFyZSBlbGlnaWJsZSB0byBqb2luIHRoZSB3b3JsZC4gT3B0aW9uYWwgaGVyZTsgcmVxdWlyZWQgd2hlbiBpbnN0YW50aWF0aW5nIHRoZSBzZXJ2aWNlIChgbmV3IEYuc2VydmljZS5Xb3JsZCgpYCkuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMucm9sZXNgIChPcHRpb25hbCkgVGhlIGxpc3Qgb2Ygcm9sZXMgKHN0cmluZ3MpIGZvciB0aGlzIHdvcmxkLiBTb21lIHdvcmxkcyBoYXZlIHNwZWNpZmljIHJvbGVzIHRoYXQgKiptdXN0KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgcm9sZXMgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIHVzZXJzIHRvIHdvcmxkcyBhbmQgZW5zdXJlIHRoYXQgYWxsIHJvbGVzIGFyZSBmaWxsZWQgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtcy5vcHRpb25hbFJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIG9wdGlvbmFsIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbWF5KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgb3B0aW9uYWwgcm9sZXMgYXMgcGFydCBvZiB0aGUgd29ybGQgb2JqZWN0IGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtpbnRlZ2VyfSBgcGFyYW1zLm1pblVzZXJzYCAoT3B0aW9uYWwpIFRoZSBtaW5pbXVtIG51bWJlciBvZiB1c2VycyBmb3IgdGhlIHdvcmxkLiBJbmNsdWRpbmcgdGhpcyBudW1iZXIgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIGVuZCB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IHRoZSBjb3JyZWN0IG51bWJlciBvZiB1c2VycyBhcmUgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9KTtcbiAgICAgICAgICAgIHZhciB3b3JsZEFwaVBhcmFtcyA9IFsnc2NvcGUnLCAnZmlsZXMnLCAncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycycsICdncm91cCcsICduYW1lJ107XG4gICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgd29ybGRBcGlQYXJhbXMpO1xuXG4gICAgICAgICAgICAvLyBhY2NvdW50IGFuZCBwcm9qZWN0IGdvIGluIHRoZSBib2R5LCBub3QgaW4gdGhlIHVybFxuICAgICAgICAgICAgJC5leHRlbmQocGFyYW1zLCBfcGljayhzZXJ2aWNlT3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSkpO1xuXG4gICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IGNyZWF0ZU9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgICAgIGNyZWF0ZU9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJlc3BvbnNlLmlkOyAvL2FsbCBmdXR1cmUgY2hhaW5lZCBjYWxscyB0byBvcGVyYXRlIG9uIHRoaXMgaWRcbiAgICAgICAgICAgICAgICByZXR1cm4gb2xkU3VjY2Vzcy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgYSBXb3JsZCwgZm9yIGV4YW1wbGUgdG8gcmVwbGFjZSB0aGUgcm9sZXMgaW4gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogVHlwaWNhbGx5LCB5b3UgY29tcGxldGUgd29ybGQgY29uZmlndXJhdGlvbiBhdCB0aGUgcHJvamVjdCBsZXZlbCwgcmF0aGVyIHRoYW4gYXQgdGhlIHdvcmxkIGxldmVsLiBGb3IgZXhhbXBsZSwgZWFjaCB3b3JsZCBpbiB5b3VyIHByb2plY3QgcHJvYmFibHkgaGFzIHRoZSBzYW1lIHJvbGVzIGZvciBlbmQgdXNlcnMuIEFuZCB5b3VyIHByb2plY3QgaXMgcHJvYmFibHkgZWl0aGVyIGNvbmZpZ3VyZWQgc28gdGhhdCBhbGwgZW5kIHVzZXJzIHNoYXJlIHRoZSBzYW1lIHdvcmxkIChhbmQgcnVuKSwgb3Igc21hbGxlciBzZXRzIG9mIGVuZCB1c2VycyBzaGFyZSB3b3JsZHMg4oCUIGJ1dCBub3QgYm90aC4gSG93ZXZlciwgdGhpcyBtZXRob2QgaXMgYXZhaWxhYmxlIGlmIHlvdSBuZWVkIHRvIHVwZGF0ZSB0aGUgY29uZmlndXJhdGlvbiBvZiBhIHBhcnRpY3VsYXIgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EudXBkYXRlKHsgcm9sZXM6IFsnVlAgTWFya2V0aW5nJywgJ1ZQIFNhbGVzJywgJ1ZQIEVuZ2luZWVyaW5nJ10gfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gdXBkYXRlIHRoZSB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5uYW1lYCBBIHN0cmluZyBpZGVudGlmaWVyIGZvciB0aGUgbGlua2VkIGVuZCB1c2VycywgZm9yIGV4YW1wbGUsIFwibmFtZVwiOiBcIk91ciBUZWFtXCIuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMucm9sZXNgIChPcHRpb25hbCkgVGhlIGxpc3Qgb2Ygcm9sZXMgKHN0cmluZ3MpIGZvciB0aGlzIHdvcmxkLiBTb21lIHdvcmxkcyBoYXZlIHNwZWNpZmljIHJvbGVzIHRoYXQgKiptdXN0KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgcm9sZXMgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIHVzZXJzIHRvIHdvcmxkcyBhbmQgZW5zdXJlIHRoYXQgYWxsIHJvbGVzIGFyZSBmaWxsZWQgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtcy5vcHRpb25hbFJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIG9wdGlvbmFsIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbWF5KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgb3B0aW9uYWwgcm9sZXMgYXMgcGFydCBvZiB0aGUgd29ybGQgb2JqZWN0IGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtpbnRlZ2VyfSBgcGFyYW1zLm1pblVzZXJzYCAoT3B0aW9uYWwpIFRoZSBtaW5pbXVtIG51bWJlciBvZiB1c2VycyBmb3IgdGhlIHdvcmxkLiBJbmNsdWRpbmcgdGhpcyBudW1iZXIgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIGVuZCB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IHRoZSBjb3JyZWN0IG51bWJlciBvZiB1c2VycyBhcmUgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgdXBkYXRlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgd2hpdGVsaXN0ID0gWydyb2xlcycsICdvcHRpb25hbFJvbGVzJywgJ21pblVzZXJzJ107XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMgfHwge30sIHdoaXRlbGlzdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKHBhcmFtcywgdXBkYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogRGVsZXRlcyBhbiBleGlzdGluZyB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFRoaXMgZnVuY3Rpb24gb3B0aW9uYWxseSB0YWtlcyBvbmUgYXJndW1lbnQuIElmIHRoZSBhcmd1bWVudCBpcyBhIHN0cmluZywgaXQgaXMgdGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUuIElmIHRoZSBhcmd1bWVudCBpcyBhbiBvYmplY3QsIGl0IGlzIHRoZSBvdmVycmlkZSBmb3IgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZGVsZXRlKCk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtTdHJpbmd8T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBUaGUgaWQgb2YgdGhlIHdvcmxkIHRvIGRlbGV0ZSwgb3Igb3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IChvcHRpb25zICYmICh0eXBlb2Ygb3B0aW9ucyA9PT0gJ3N0cmluZycpKSA/IHsgZmlsdGVyOiBvcHRpb25zIH0gOiB7fTtcbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogVXBkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBmb3IgdGhlIGN1cnJlbnQgaW5zdGFuY2Ugb2YgdGhlIFdvcmxkIEFQSSBBZGFwdGVyIChpbmNsdWRpbmcgYWxsIHN1YnNlcXVlbnQgZnVuY3Rpb24gY2FsbHMsIHVudGlsIHRoZSBjb25maWd1cmF0aW9uIGlzIHVwZGF0ZWQgYWdhaW4pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7Li4ufSkudXBkYXRlQ29uZmlnKHsgZmlsdGVyOiAnMTIzJyB9KS5hZGRVc2VyKHsgdXNlcklkOiAnMTIzJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBjb25maWdgIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB0byB1c2UgaW4gdXBkYXRpbmcgZXhpc3RpbmcgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKi9cbiAgICAgICAgdXBkYXRlQ29uZmlnOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICAkLmV4dGVuZChzZXJ2aWNlT3B0aW9ucywgY29uZmlnKTtcblxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogTGlzdHMgYWxsIHdvcmxkcyBmb3IgYSBnaXZlbiBhY2NvdW50LCBwcm9qZWN0LCBhbmQgZ3JvdXAuIEFsbCB0aHJlZSBhcmUgcmVxdWlyZWQsIGFuZCBpZiBub3Qgc3BlY2lmaWVkIGFzIHBhcmFtZXRlcnMsIGFyZSByZWFkIGZyb20gdGhlIHNlcnZpY2UuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gbGlzdHMgYWxsIHdvcmxkcyBpbiBncm91cCBcInRlYW0xXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgICAgICAgLy8gbGlzdHMgYWxsIHdvcmxkcyBpbiBncm91cCBcIm90aGVyLWdyb3VwLW5hbWVcIlxuICAgICAgICAqICAgICAgICAgICAgICAgd2EubGlzdCh7IGdyb3VwOiAnb3RoZXItZ3JvdXAtbmFtZScgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIGZpbHRlcnMgPSBfcGljayhnZXRPcHRpb25zLCBbJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCddKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgYWxsIHdvcmxkcyB0aGF0IGFuIGVuZCB1c2VyIGJlbG9uZ3MgdG8gZm9yIGEgZ2l2ZW4gYWNjb3VudCAodGVhbSksIHByb2plY3QsIGFuZCBncm91cC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRXb3JsZHNGb3JVc2VyKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnKVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJJZGAgVGhlIGB1c2VySWRgIG9mIHRoZSB1c2VyIHdob3NlIHdvcmxkcyBhcmUgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0V29ybGRzRm9yVXNlcjogZnVuY3Rpb24gKHVzZXJJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gJC5leHRlbmQoXG4gICAgICAgICAgICAgICAgX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSksXG4gICAgICAgICAgICAgICAgeyB1c2VySWQ6IHVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoZmlsdGVycywgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvYWQgaW5mb3JtYXRpb24gZm9yIGEgc3BlY2lmaWMgd29ybGQuIEFsbCBmdXJ0aGVyIGNhbGxzIHRvIHRoZSB3b3JsZCBzZXJ2aWNlIHdpbGwgdXNlIHRoZSBpZCBwcm92aWRlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGB3b3JsZElkYCBUaGUgaWQgb2YgdGhlIHdvcmxkIHRvIGxvYWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBpZiAod29ybGRJZCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHByb3ZpZGUgYSB3b3JsZGlkIHRvIGxvYWQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnLycgfSk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoJycsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBBZGRzIGFuIGVuZCB1c2VyIG9yIGxpc3Qgb2YgZW5kIHVzZXJzIHRvIGEgZ2l2ZW4gd29ybGQuIFRoZSBlbmQgdXNlciBtdXN0IGJlIGEgbWVtYmVyIG9mIHRoZSBgZ3JvdXBgIHRoYXQgaXMgYXNzb2NpYXRlZCB3aXRoIHRoaXMgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gYWRkIG9uZSB1c2VyXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMyddKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKHsgdXNlcklkOiAnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgcm9sZTogJ1ZQIFNhbGVzJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgICAgICAgLy8gYWRkIHNldmVyYWwgdXNlcnNcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKFtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgTWFya2V0aW5nJyB9LFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgdXNlcklkOiAnOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgIHJvbGU6ICdWUCBFbmdpbmVlcmluZycgfVxuICAgICAgICAqICAgICAgICAgICAgICAgXSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlciB0byBhIHNwZWNpZmljIHdvcmxkXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgd29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHsgZmlsdGVyOiB3b3JsZC5pZCB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fGFycmF5fSBgdXNlcnNgIFVzZXIgaWQsIGFycmF5IG9mIHVzZXIgaWRzLCBvYmplY3QsIG9yIGFycmF5IG9mIG9iamVjdHMgb2YgdGhlIHVzZXJzIHRvIGFkZCB0byB0aGlzIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcnMucm9sZWAgVGhlIGByb2xlYCB0aGUgdXNlciBzaG91bGQgaGF2ZSBpbiB0aGUgd29ybGQuIEl0IGlzIHVwIHRvIHRoZSBjYWxsZXIgdG8gZW5zdXJlLCBpZiBuZWVkZWQsIHRoYXQgdGhlIGByb2xlYCBwYXNzZWQgaW4gaXMgb25lIG9mIHRoZSBgcm9sZXNgIG9yIGBvcHRpb25hbFJvbGVzYCBvZiB0aGlzIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgVGhlIHdvcmxkIHRvIHdoaWNoIHRoZSB1c2VycyBzaG91bGQgYmUgYWRkZWQuIElmIG5vdCBzcGVjaWZpZWQsIHRoZSBmaWx0ZXIgcGFyYW1ldGVyIG9mIHRoZSBgb3B0aW9uc2Agb2JqZWN0IGlzIHVzZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBhZGRVc2VyczogZnVuY3Rpb24gKHVzZXJzLCB3b3JsZElkLCBvcHRpb25zKSB7XG5cbiAgICAgICAgICAgIGlmICghdXNlcnMpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgbGlzdCBvZiB1c2VycyB0byBhZGQgdG8gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG5vcm1hbGl6ZSB0aGUgbGlzdCBvZiB1c2VycyB0byBhbiBhcnJheSBvZiB1c2VyIG9iamVjdHNcbiAgICAgICAgICAgIHVzZXJzID0gJC5tYXAoW10uY29uY2F0KHVzZXJzKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QodSk7XG5cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHUgIT09ICdzdHJpbmcnICYmICFpc09iamVjdCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NvbWUgb2YgdGhlIHVzZXJzIGluIHRoZSBsaXN0IGFyZSBub3QgaW4gdGhlIHZhbGlkIGZvcm1hdDogJyArIHUpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBpc09iamVjdCA/IHUgOiB7IHVzZXJJZDogdSB9O1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIG9wdGlvbnMgd2VyZSBwYXNzZWQgYXMgdGhlIHNlY29uZCBwYXJhbWV0ZXJcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qod29ybGRJZCkgJiYgIW9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zID0gd29ybGRJZDtcbiAgICAgICAgICAgICAgICB3b3JsZElkID0gbnVsbDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIC8vIHdlIG11c3QgaGF2ZSBvcHRpb25zIGJ5IG5vd1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB3b3JsZElkID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZmlsdGVyID0gd29ybGRJZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciB1cGRhdGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2VycycgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh1c2VycywgdXBkYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogVXBkYXRlcyB0aGUgcm9sZSBvZiBhbiBlbmQgdXNlciBpbiBhIGdpdmVuIHdvcmxkLiAoWW91IGNhbiBvbmx5IHVwZGF0ZSBvbmUgZW5kIHVzZXIgYXQgYSB0aW1lLilcbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKS50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnKTtcbiAgICAgICAgKiAgICAgICAgICAgd2EudXBkYXRlVXNlcih7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdsZWFkZXInIH0pO1xuICAgICAgICAqICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgdXNlcmAgVXNlciBvYmplY3Qgd2l0aCBgdXNlcklkYCBhbmQgdGhlIG5ldyBgcm9sZWAuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZVVzZXI6IGZ1bmN0aW9uICh1c2VyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKCF1c2VyIHx8ICF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byB1cGRhdGUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBwYXRjaE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3VzZXJzLycgKyB1c2VyLnVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChfcGljayh1c2VyLCAncm9sZScpLCBwYXRjaE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlbW92ZXMgYW4gZW5kIHVzZXIgZnJvbSBhIGdpdmVuIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKFsnYTZmZTBjMWUtZjRiOC00ZjAxLTlmNWYtMDFjY2Y0YzJlZDQ0JywgJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZSddKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EucmVtb3ZlVXNlcih7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fHN0cmluZ30gYHVzZXJgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQsIG9yIGFuIG9iamVjdCBjb250YWluaW5nIHRoZSBgdXNlcklkYCBmaWVsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIHJlbW92ZVVzZXI6IGZ1bmN0aW9uICh1c2VyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiB1c2VyID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIHVzZXIgPSB7IHVzZXJJZDogdXNlciB9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIXVzZXIudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgbmVlZCB0byBwYXNzIGEgdXNlcklkIHRvIHJlbW92ZSBmcm9tIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3VzZXJzLycgKyB1c2VyLnVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyB0aGUgcnVuIGlkIG9mIGN1cnJlbnQgcnVuIGZvciB0aGUgZ2l2ZW4gd29ybGQuIElmIHRoZSB3b3JsZCBkb2VzIG5vdCBoYXZlIGEgcnVuLCBjcmVhdGVzIGEgbmV3IG9uZSBhbmQgcmV0dXJucyB0aGUgcnVuIGlkLlxuICAgICAgICAqXG4gICAgICAgICogUmVtZW1iZXIgdGhhdCBhIFtydW5dKC4uLy4uL2dsb3NzYXJ5LyNydW4pIGlzIGEgY29sbGVjdGlvbiBvZiBpbnRlcmFjdGlvbnMgd2l0aCBhIHByb2plY3QgYW5kIGl0cyBtb2RlbC4gSW4gdGhlIGNhc2Ugb2YgbXVsdGlwbGF5ZXIgcHJvamVjdHMsIHRoZSBydW4gaXMgc2hhcmVkIGJ5IGFsbCBlbmQgdXNlcnMgaW4gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiAnbW9kZWwucHknIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zLm1vZGVsYCBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIGEgcnVuIGlmIG5lZWRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bklkOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YWxpZGF0ZU1vZGVsT3JUaHJvd0Vycm9yKGdldE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChfcGljayhnZXRPcHRpb25zLCAnbW9kZWwnKSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyB0aGUgY3VycmVudCAobW9zdCByZWNlbnQpIHdvcmxkIGZvciB0aGUgZ2l2ZW4gZW5kIHVzZXIgaW4gdGhlIGdpdmVuIGdyb3VwLiBCcmluZ3MgdGhpcyBtb3N0IHJlY2VudCB3b3JsZCBpbnRvIG1lbW9yeSBpZiBuZWVkZWQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKCc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gdXNlIGRhdGEgZnJvbSB3b3JsZFxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJJZGAgVGhlIGB1c2VySWRgIG9mIHRoZSB1c2VyIHdob3NlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBpcyBiZWluZyByZXRyaWV2ZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgVGhlIG5hbWUgb2YgdGhlIGdyb3VwLiBJZiBub3QgcHJvdmlkZWQsIGRlZmF1bHRzIHRvIHRoZSBncm91cCB1c2VkIHRvIGNyZWF0ZSB0aGUgc2VydmljZS5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkRm9yVXNlcjogZnVuY3Rpb24gKHVzZXJJZCwgZ3JvdXBOYW1lKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHRoaXMuZ2V0V29ybGRzRm9yVXNlcih1c2VySWQsIHsgZ3JvdXA6IGdyb3VwTmFtZSB9KVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gYXNzdW1lIHRoZSBtb3N0IHJlY2VudCB3b3JsZCBhcyB0aGUgJ2FjdGl2ZScgd29ybGRcbiAgICAgICAgICAgICAgICAgICAgd29ybGRzLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIubGFzdE1vZGlmaWVkKSAtIG5ldyBEYXRlKGEubGFzdE1vZGlmaWVkKTsgfSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGQgPSB3b3JsZHNbMF07XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGN1cnJlbnRXb3JsZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gIGN1cnJlbnRXb3JsZC5pZDtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGN1cnJlbnRXb3JsZCwgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgdGhlIGN1cnJlbnQgcnVuIGZyb20gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogKE5vdGUgdGhhdCB0aGUgd29ybGQgaWQgcmVtYWlucyBwYXJ0IG9mIHRoZSBydW4gcmVjb3JkLCBpbmRpY2F0aW5nIHRoYXQgdGhlIHJ1biB3YXMgZm9ybWVybHkgYW4gYWN0aXZlIHJ1biBmb3IgdGhlIHdvcmxkLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZGVsZXRlUnVuKCdzYW1wbGUtd29ybGQtaWQnKTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgVGhlIGB3b3JsZElkYCBvZiB0aGUgd29ybGQgZnJvbSB3aGljaCB0aGUgY3VycmVudCBydW4gaXMgYmVpbmcgZGVsZXRlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZVJ1bjogZnVuY3Rpb24gKHdvcmxkSWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBpZiAod29ybGRJZCkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZmlsdGVyID0gd29ybGRJZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkZWxldGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy9ydW4nIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmRlbGV0ZShudWxsLCBkZWxldGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBDcmVhdGVzIGEgbmV3IHJ1biBmb3IgdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKCc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB3YS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB3b3JsZElkYCB3b3JsZElkIGluIHdoaWNoIHdlIGNyZWF0ZSB0aGUgbmV3IHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zLm1vZGVsYCBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIGEgcnVuIGlmIG5lZWRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgbmV3UnVuRm9yV29ybGQ6IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY3VycmVudFJ1bk9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgZmlsdGVyOiB3b3JsZElkIHx8IHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihjdXJyZW50UnVuT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzLmRlbGV0ZVJ1bih3b3JsZElkLCBvcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLmdldEN1cnJlbnRSdW5JZChjdXJyZW50UnVuT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQXNzaWducyBlbmQgdXNlcnMgdG8gd29ybGRzLCBjcmVhdGluZyBuZXcgd29ybGRzIGFzIGFwcHJvcHJpYXRlLCBhdXRvbWF0aWNhbGx5LiBBc3NpZ25zIGFsbCBlbmQgdXNlcnMgaW4gdGhlIGdyb3VwLCBhbmQgY3JlYXRlcyBuZXcgd29ybGRzIGFzIG5lZWRlZCBiYXNlZCBvbiB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIChyb2xlcywgb3B0aW9uYWwgcm9sZXMsIGFuZCBtaW5pbXVtIGVuZCB1c2VycyBwZXIgd29ybGQpLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmF1dG9Bc3NpZ24oKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGF1dG9Bc3NpZ246IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFzc2lnbm1lbnRFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIHBhcmFtcyA9IHtcbiAgICAgICAgICAgICAgICBhY2NvdW50OiBvcHQuYWNjb3VudCxcbiAgICAgICAgICAgICAgICBwcm9qZWN0OiBvcHQucHJvamVjdCxcbiAgICAgICAgICAgICAgICBncm91cDogb3B0Lmdyb3VwXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAob3B0Lm1heFVzZXJzKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zLm1heFVzZXJzID0gb3B0Lm1heFVzZXJzO1xuICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBvcHQpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHByb2plY3QncyB3b3JsZCBjb25maWd1cmF0aW9uLlxuICAgICAgICAqXG4gICAgICAgICogVHlwaWNhbGx5LCBldmVyeSBpbnRlcmFjdGlvbiB3aXRoIHlvdXIgcHJvamVjdCB1c2VzIHRoZSBzYW1lIGNvbmZpZ3VyYXRpb24gb2YgZWFjaCB3b3JsZC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguXG4gICAgICAgICpcbiAgICAgICAgKiAoVGhlIFtNdWx0aXBsYXllciBQcm9qZWN0IFJFU1QgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvbXVsdGlwbGF5ZXJfcHJvamVjdC8pIGFsbG93cyB5b3UgdG8gc2V0IHRoZXNlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbnMuIFRoZSBXb3JsZCBBZGFwdGVyIHNpbXBseSByZXRyaWV2ZXMgdGhlbSwgZm9yIGV4YW1wbGUgc28gdGhleSBjYW4gYmUgdXNlZCBpbiBhdXRvLWFzc2lnbm1lbnQgb2YgZW5kIHVzZXJzIHRvIHdvcmxkcy4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0UHJvamVjdFNldHRpbmdzKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc2V0dGluZ3MpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHNldHRpbmdzLnJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHNldHRpbmdzLm9wdGlvbmFsUm9sZXMpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBnZXRQcm9qZWN0U2V0dGluZ3M6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKHByb2plY3RFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgb3B0LnVybCArPSBbb3B0LmFjY291bnQsIG9wdC5wcm9qZWN0XS5qb2luKCcvJyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChudWxsLCBvcHQpO1xuICAgICAgICB9XG5cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqIEBjbGFzcyBDb29raWUgU3RvcmFnZSBTZXJ2aWNlXG4gKlxuICogQGV4YW1wbGVcbiAqICAgICAgdmFyIHBlb3BsZSA9IHJlcXVpcmUoJ2Nvb2tpZS1zdG9yZScpKHsgcm9vdDogJ3Blb3BsZScgfSk7XG4gICAgICAgIHBlb3BsZVxuICAgICAgICAgICAgLnNhdmUoe2xhc3ROYW1lOiAnc21pdGgnIH0pXG5cbiAqL1xuXG5cbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogTmFtZSBvZiBjb2xsZWN0aW9uXG4gICAgICAgICAqIEB0eXBlIHsgc3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcm9vdDogJy8nLFxuXG4gICAgICAgIGRvbWFpbjogJy5mb3Jpby5jb20nXG4gICAgfTtcbiAgICB0aGlzLnNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLy8gKiBUQkRcbiAgICAgICAgLy8gICogUXVlcnkgY29sbGVjdGlvbjsgdXNlcyBNb25nb0RCIHN5bnRheFxuICAgICAgICAvLyAgKiBAc2VlICA8VEJEOiBEYXRhIEFQSSBVUkw+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gcXMgUXVlcnkgRmlsdGVyXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gbGltaXRlcnMgQHNlZSA8VEJEOiB1cmwgZm9yIGxpbWl0cywgcGFnaW5nIGV0Yz5cbiAgICAgICAgLy8gICpcbiAgICAgICAgLy8gICogQGV4YW1wbGVcbiAgICAgICAgLy8gICogICAgIGNzLnF1ZXJ5KFxuICAgICAgICAvLyAgKiAgICAgIHsgbmFtZTogJ0pvaG4nLCBjbGFzc05hbWU6ICdDU0MxMDEnIH0sXG4gICAgICAgIC8vICAqICAgICAge2xpbWl0OiAxMH1cbiAgICAgICAgLy8gICogICAgIClcblxuICAgICAgICAvLyBxdWVyeTogZnVuY3Rpb24gKHFzLCBsaW1pdGVycykge1xuXG4gICAgICAgIC8vIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgY29va2llIHZhbHVlXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8T2JqZWN0fSBrZXkgICBJZiBnaXZlbiBhIGtleSBzYXZlIHZhbHVlcyB1bmRlciBpdCwgaWYgZ2l2ZW4gYW4gb2JqZWN0IGRpcmVjdGx5LCBzYXZlIHRvIHRvcC1sZXZlbCBhcGlcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSB2YWx1ZSAoT3B0aW9uYWwpXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIE92ZXJyaWRlcyBmb3Igc2VydmljZSBvcHRpb25zXG4gICAgICAgICAqXG4gICAgICAgICAqIEByZXR1cm4geyp9IFRoZSBzYXZlZCB2YWx1ZVxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3Muc2V0KCdwZXJzb24nLCB7IGZpcnN0TmFtZTogJ2pvaG4nLCBsYXN0TmFtZTogJ3NtaXRoJyB9KTtcbiAgICAgICAgICogICAgIGNzLnNldCh7IG5hbWU6J3NtaXRoJywgYWdlOiczMicgfSk7XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgc2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLnNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRvbWFpbiA9IHNldE9wdGlvbnMuZG9tYWluO1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXRPcHRpb25zLnJvb3Q7XG5cbiAgICAgICAgICAgIGRvY3VtZW50LmNvb2tpZSA9IGVuY29kZVVSSUNvbXBvbmVudChrZXkpICsgJz0nICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5jb2RlVVJJQ29tcG9uZW50KHZhbHVlKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChkb21haW4gPyAnOyBkb21haW49JyArIGRvbWFpbiA6ICcnKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwYXRoID8gJzsgcGF0aD0nICsgcGF0aCA6ICcnKTtcblxuICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGNvb2tpZSB2YWx1ZVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5ICAgSWYgZ2l2ZW4gYSBrZXkgc2F2ZSB2YWx1ZXMgdW5kZXIgaXQsIGlmIGdpdmVuIGFuIG9iamVjdCBkaXJlY3RseSwgc2F2ZSB0byB0b3AtbGV2ZWwgYXBpXG4gICAgICAgICAqIEByZXR1cm4geyp9IFRoZSB2YWx1ZSBzdG9yZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLmdldCgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHZhciBjb29raWVSZWcgPSBuZXcgUmVnRXhwKCcoPzooPzpefC4qOylcXFxccyonICsgZW5jb2RlVVJJQ29tcG9uZW50KGtleSkucmVwbGFjZSgvW1xcLVxcLlxcK1xcKl0vZywgJ1xcXFwkJicpICsgJ1xcXFxzKlxcXFw9XFxcXHMqKFteO10qKS4qJCl8Xi4qJCcpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IGRvY3VtZW50LmNvb2tpZS5yZXBsYWNlKGNvb2tpZVJlZywgJyQxJyk7XG4gICAgICAgICAgICB2YWwgPSBkZWNvZGVVUklDb21wb25lbnQodmFsKSB8fCBudWxsO1xuICAgICAgICAgICAgcmV0dXJuIHZhbDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBrZXkgZnJvbSBjb2xsZWN0aW9uXG4gICAgICAgICAqIEBwYXJhbSB7IHN0cmluZ30ga2V5IGtleSB0byByZW1vdmVcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ30ga2V5IFRoZSBrZXkgcmVtb3ZlZFxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3MucmVtb3ZlKCdwZXJzb24nKTtcbiAgICAgICAgICovXG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHJlbU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5zZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSByZW1PcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gcmVtT3B0aW9ucy5yb290O1xuXG4gICAgICAgICAgICBkb2N1bWVudC5jb29raWUgPSBlbmNvZGVVUklDb21wb25lbnQoa2V5KSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJz07IGV4cGlyZXM9VGh1LCAwMSBKYW4gMTk3MCAwMDowMDowMCBHTVQnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwYXRoID8gJzsgcGF0aD0nICsgcGF0aCA6ICcnKTtcbiAgICAgICAgICAgIHJldHVybiBrZXk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMgY29sbGVjdGlvbiBiZWluZyByZWZlcmVuY2VkXG4gICAgICAgICAqIEByZXR1cm4geyBhcnJheX0ga2V5cyBBbGwgdGhlIGtleXMgcmVtb3ZlZFxuICAgICAgICAgKi9cbiAgICAgICAgZGVzdHJveTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFLZXlzID0gZG9jdW1lbnQuY29va2llLnJlcGxhY2UoLygoPzpefFxccyo7KVteXFw9XSspKD89O3wkKXxeXFxzKnxcXHMqKD86XFw9W147XSopPyg/OlxcMXwkKS9nLCAnJykuc3BsaXQoL1xccyooPzpcXD1bXjtdKik/O1xccyovKTtcbiAgICAgICAgICAgIGZvciAodmFyIG5JZHggPSAwOyBuSWR4IDwgYUtleXMubGVuZ3RoOyBuSWR4KyspIHtcbiAgICAgICAgICAgICAgICB2YXIgY29va2llS2V5ID0gZGVjb2RlVVJJQ29tcG9uZW50KGFLZXlzW25JZHhdKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbW92ZShjb29raWVLZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFLZXlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gICAgRGVjaWRlcyB0eXBlIG9mIHN0b3JlIHRvIHByb3ZpZGVcbiovXG5cbid1c2Ugc3RyaWN0Jztcbi8vIHZhciBpc05vZGUgPSBmYWxzZTsgRklYTUU6IEJyb3dzZXJpZnkvbWluaWZ5aWZ5IGhhcyBpc3N1ZXMgd2l0aCB0aGUgbmV4dCBsaW5rXG4vLyB2YXIgc3RvcmUgPSAoaXNOb2RlKSA/IHJlcXVpcmUoJy4vc2Vzc2lvbi1zdG9yZScpIDogcmVxdWlyZSgnLi9jb29raWUtc3RvcmUnKTtcbnZhciBzdG9yZSA9IHJlcXVpcmUoJy4vY29va2llLXN0b3JlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gc3RvcmU7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBxdXRpbHMgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIHVybDogJycsXG5cbiAgICAgICAgY29udGVudFR5cGU6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICAgaGVhZGVyczoge30sXG4gICAgICAgIHN0YXR1c0NvZGU6IHtcbiAgICAgICAgICAgIDQwNDogJC5ub29wXG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9OTFkgZm9yIHN0cmluZ3MgaW4gdGhlIHVybC4gQWxsIEdFVCAmIERFTEVURSBwYXJhbXMgYXJlIHJ1biB0aHJvdWdoIHRoaXNcbiAgICAgICAgICogQHR5cGUge1t0eXBlXSB9XG4gICAgICAgICAqL1xuICAgICAgICBwYXJhbWV0ZXJQYXJzZXI6IHF1dGlscy50b1F1ZXJ5Rm9ybWF0LFxuXG4gICAgICAgIC8vIFRvIGFsbG93IGVwaWNlbnRlci50b2tlbiBhbmQgb3RoZXIgc2Vzc2lvbiBjb29raWVzIHRvIGJlIHBhc3NlZFxuICAgICAgICAvLyB3aXRoIHRoZSByZXF1ZXN0c1xuICAgICAgICB4aHJGaWVsZHM6IHtcbiAgICAgICAgICAgIHdpdGhDcmVkZW50aWFsczogdHJ1ZVxuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHJlc3VsdCA9IGZ1bmN0aW9uIChkKSB7XG4gICAgICAgIHJldHVybiAoJC5pc0Z1bmN0aW9uKGQpKSA/IGQoKSA6IGQ7XG4gICAgfTtcblxuICAgIHZhciBjb25uZWN0ID0gZnVuY3Rpb24gKG1ldGhvZCwgcGFyYW1zLCBjb25uZWN0T3B0aW9ucykge1xuICAgICAgICBwYXJhbXMgPSByZXN1bHQocGFyYW1zKTtcbiAgICAgICAgcGFyYW1zID0gKCQuaXNQbGFpbk9iamVjdChwYXJhbXMpIHx8ICQuaXNBcnJheShwYXJhbXMpKSA/IEpTT04uc3RyaW5naWZ5KHBhcmFtcykgOiBwYXJhbXM7XG5cbiAgICAgICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdHJhbnNwb3J0T3B0aW9ucywgY29ubmVjdE9wdGlvbnMsIHtcbiAgICAgICAgICAgIHR5cGU6IG1ldGhvZCxcbiAgICAgICAgICAgIGRhdGE6IHBhcmFtc1xuICAgICAgICB9KTtcbiAgICAgICAgdmFyIEFMTE9XRURfVE9fQkVfRlVOQ1RJT05TID0gWydkYXRhJywgJ3VybCddO1xuICAgICAgICAkLmVhY2gob3B0aW9ucywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgIGlmICgkLmlzRnVuY3Rpb24odmFsdWUpICYmICQuaW5BcnJheShrZXksIEFMTE9XRURfVE9fQkVfRlVOQ1RJT05TKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zW2tleV0gPSB2YWx1ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAob3B0aW9ucy5sb2dMZXZlbCAmJiBvcHRpb25zLmxvZ0xldmVsID09PSAnREVCVUcnKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhvcHRpb25zLnVybCk7XG4gICAgICAgICAgICB2YXIgb2xkU3VjY2Vzc0ZuID0gb3B0aW9ucy5zdWNjZXNzIHx8ICQubm9vcDtcbiAgICAgICAgICAgIG9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSwgYWpheFN0YXR1cywgYWpheFJlcSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICBvbGRTdWNjZXNzRm4uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYmVmb3JlU2VuZCA9IG9wdGlvbnMuYmVmb3JlU2VuZDtcbiAgICAgICAgb3B0aW9ucy5iZWZvcmVTZW5kID0gZnVuY3Rpb24gKHhociwgc2V0dGluZ3MpIHtcbiAgICAgICAgICAgIHhoci5yZXF1ZXN0VXJsID0gKGNvbm5lY3RPcHRpb25zIHx8IHt9KS51cmw7XG4gICAgICAgICAgICBpZiAoYmVmb3JlU2VuZCkge1xuICAgICAgICAgICAgICAgIGJlZm9yZVNlbmQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gJC5hamF4KG9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICBnZXQ6ZnVuY3Rpb24gKHBhcmFtcywgYWpheE9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRyYW5zcG9ydE9wdGlvbnMsIGFqYXhPcHRpb25zKTtcbiAgICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1ldGVyUGFyc2VyKHJlc3VsdChwYXJhbXMpKTtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmNhbGwodGhpcywgJ0dFVCcsIHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgIH0sXG4gICAgICAgIHNwbGl0R2V0OiBmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgfSxcbiAgICAgICAgcG9zdDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwb3N0J10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBwYXRjaDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwYXRjaCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgcHV0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ3B1dCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAocGFyYW1zLCBhamF4T3B0aW9ucykge1xuICAgICAgICAgICAgLy9ERUxFVEUgZG9lc24ndCBzdXBwb3J0IGJvZHkgcGFyYW1zLCBidXQgalF1ZXJ5IHRoaW5rcyBpdCBkb2VzLlxuICAgICAgICAgICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgdHJhbnNwb3J0T3B0aW9ucywgYWpheE9wdGlvbnMpO1xuICAgICAgICAgICAgcGFyYW1zID0gb3B0aW9ucy5wYXJhbWV0ZXJQYXJzZXIocmVzdWx0KHBhcmFtcykpO1xuICAgICAgICAgICAgaWYgKCQudHJpbShwYXJhbXMpKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRlbGltaXRlciA9IChyZXN1bHQob3B0aW9ucy51cmwpLmluZGV4T2YoJz8nKSA9PT0gLTEpID8gJz8nIDogJyYnO1xuICAgICAgICAgICAgICAgIG9wdGlvbnMudXJsID0gcmVzdWx0KG9wdGlvbnMudXJsKSArIGRlbGltaXRlciArIHBhcmFtcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmNhbGwodGhpcywgJ0RFTEVURScsIG51bGwsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuICAgICAgICBoZWFkOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ2hlYWQnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIG9wdGlvbnM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsnb3B0aW9ucyddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICByZXR1cm4gJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbi8vIHZhciBpc05vZGUgPSBmYWxzZTsgRklYTUU6IEJyb3dzZXJpZnkvbWluaWZ5aWZ5IGhhcyBpc3N1ZXMgd2l0aCB0aGUgbmV4dCBsaW5rXG4vLyB2YXIgdHJhbnNwb3J0ID0gKGlzTm9kZSkgPyByZXF1aXJlKCcuL25vZGUtaHR0cC10cmFuc3BvcnQnKSA6IHJlcXVpcmUoJy4vYWpheC1odHRwLXRyYW5zcG9ydCcpO1xudmFyIHRyYW5zcG9ydCA9IHJlcXVpcmUoJy4vYWpheC1odHRwLXRyYW5zcG9ydCcpO1xubW9kdWxlLmV4cG9ydHMgPSB0cmFuc3BvcnQ7XG4iLCIvKipcbi8qIEluaGVyaXQgZnJvbSBhIGNsYXNzICh1c2luZyBwcm90b3R5cGUgYm9ycm93aW5nKVxuKi9cbid1c2Ugc3RyaWN0JztcblxuZnVuY3Rpb24gaW5oZXJpdChDLCBQKSB7XG4gICAgdmFyIEYgPSBmdW5jdGlvbiAoKSB7fTtcbiAgICBGLnByb3RvdHlwZSA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlID0gbmV3IEYoKTtcbiAgICBDLl9fc3VwZXIgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEM7XG59XG5cbi8qKlxuKiBTaGFsbG93IGNvcHkgb2YgYW4gb2JqZWN0XG4qL1xudmFyIGV4dGVuZCA9IGZ1bmN0aW9uIChkZXN0IC8qLCB2YXJfYXJncyovKSB7XG4gICAgdmFyIG9iaiA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgdmFyIGN1cnJlbnQ7XG4gICAgZm9yICh2YXIgaiA9IDA7IGo8b2JqLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIGlmICghKGN1cnJlbnQgPSBvYmpbal0pKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGRvIG5vdCB3cmFwIGlubmVyIGluIGRlc3QuaGFzT3duUHJvcGVydHkgb3IgYmFkIHRoaW5ncyB3aWxsIGhhcHBlblxuICAgICAgICAvKmpzaGludCAtVzA4OSAqL1xuICAgICAgICBmb3IgKHZhciBrZXkgaW4gY3VycmVudCkge1xuICAgICAgICAgICAgZGVzdFtrZXldID0gY3VycmVudFtrZXldO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGRlc3Q7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChiYXNlLCBwcm9wcywgc3RhdGljUHJvcHMpIHtcbiAgICB2YXIgcGFyZW50ID0gYmFzZTtcbiAgICB2YXIgY2hpbGQ7XG5cbiAgICBjaGlsZCA9IHByb3BzICYmIHByb3BzLmhhc093blByb3BlcnR5KCdjb25zdHJ1Y3RvcicpID8gcHJvcHMuY29uc3RydWN0b3IgOiBmdW5jdGlvbiAoKSB7IHJldHVybiBwYXJlbnQuYXBwbHkodGhpcywgYXJndW1lbnRzKTsgfTtcblxuICAgIC8vIGFkZCBzdGF0aWMgcHJvcGVydGllcyB0byB0aGUgY2hpbGQgY29uc3RydWN0b3IgZnVuY3Rpb25cbiAgICBleHRlbmQoY2hpbGQsIHBhcmVudCwgc3RhdGljUHJvcHMpO1xuXG4gICAgLy8gYXNzb2NpYXRlIHByb3RvdHlwZSBjaGFpblxuICAgIGluaGVyaXQoY2hpbGQsIHBhcmVudCk7XG5cbiAgICAvLyBhZGQgaW5zdGFuY2UgcHJvcGVydGllc1xuICAgIGlmIChwcm9wcykge1xuICAgICAgICBleHRlbmQoY2hpbGQucHJvdG90eXBlLCBwcm9wcyk7XG4gICAgfVxuXG4gICAgLy8gZG9uZVxuICAgIHJldHVybiBjaGlsZDtcbn07XG4iLCIndXNlIHN0cmljdCc7XG4vKmpzaGludCBsb29wZnVuYzpmYWxzZSAqL1xuXG5mdW5jdGlvbiBfdyh2YWwpIHtcbiAgICBpZiAodmFsICYmIHZhbC50aGVuKSB7XG4gICAgICAgIHJldHVybiB2YWw7XG4gICAgfVxuICAgIHZhciBwID0gJC5EZWZlcnJlZCgpO1xuICAgIHAucmVzb2x2ZSh2YWwpO1xuXG4gICAgcmV0dXJuIHAucHJvbWlzZSgpO1xufVxuXG5mdW5jdGlvbiBzZXEoKSB7XG4gICAgdmFyIGxpc3QgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuYXBwbHkoYXJndW1lbnRzKTtcblxuICAgIGZ1bmN0aW9uIG5leHQocCkge1xuICAgICAgICB2YXIgY3VyID0gbGlzdC5zcGxpY2UoMCwxKVswXTtcblxuICAgICAgICBpZiAoIWN1cikge1xuICAgICAgICAgICAgcmV0dXJuIHA7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX3coY3VyKHApKS50aGVuKG5leHQpO1xuICAgIH1cblxuICAgIHJldHVybiBmdW5jdGlvbiAoc2VlZCkge1xuICAgICAgICByZXR1cm4gbmV4dChzZWVkKS5mYWlsKHNlcS5mYWlsKTtcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBNYWtlU2VxKG9iaikge1xuICAgIHZhciByZXMgPSB7XG4gICAgICAgIF9fY2FsbHM6IFtdLFxuXG4gICAgICAgIG9yaWdpbmFsOiBvYmosXG5cbiAgICAgICAgdGhlbjogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgICAgICB0aGlzLl9fY2FsbHMucHVzaChmbik7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfSxcblxuICAgICAgICBzdGFydDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgICAgICAgICAgLy8gY2xlYW4gdXBcbiAgICAgICAgICAgIHRoaXMudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMuX19jYWxscy5sZW5ndGggPSAwO1xuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIHNlcS5hcHBseShudWxsLCB0aGlzLl9fY2FsbHMpKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgZmFpbDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgICAgICBzZXEuZmFpbCA9IGZuO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIGZ1bmNNYWtlciA9IGZ1bmN0aW9uIChwLCBvYmopIHtcbiAgICAgICAgdmFyIGZuID0gb2JqW3BdLmJpbmQob2JqKTtcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmFwcGx5KGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB0aGlzLl9fY2FsbHMucHVzaChGdW5jdGlvbi5iaW5kLmFwcGx5KGZuLCBbbnVsbF0uY29uY2F0KGFyZ3MpKSk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfTtcbiAgICB9O1xuXG4gICAgZm9yICh2YXIgcHJvcCBpbiBvYmopIHtcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpbcHJvcF0gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIHJlc1twcm9wXSA9IGZ1bmNNYWtlcihwcm9wLCBvYmopO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVzW3Byb3BdID0gb2JqW3Byb3BdO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlcztcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBNYWtlU2VxO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBfcGljazogZnVuY3Rpb24gKG9iaiwgcHJvcHMpIHtcbiAgICAgICAgdmFyIHJlcyA9IHt9O1xuICAgICAgICBmb3IgKHZhciBwIGluIG9iaikge1xuICAgICAgICAgICAgaWYgKHByb3BzLmluZGV4T2YocCkgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgcmVzW3BdID0gb2JqW3BdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG59O1xuIiwiLyoqXG4gKiBVdGlsaXRpZXMgZm9yIHdvcmtpbmcgd2l0aCBxdWVyeSBzdHJpbmdzXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IChmdW5jdGlvbiAoKSB7XG5cbiAgICByZXR1cm4ge1xuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgdG8gbWF0cml4IGZvcm1hdFxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IHFzIE9iamVjdCB0byBjb252ZXJ0IHRvIHF1ZXJ5IHN0cmluZ1xuICAgICAgICAgKiBAcmV0dXJuIHsgc3RyaW5nfSAgICBNYXRyaXgtZm9ybWF0IHF1ZXJ5IHBhcmFtZXRlcnNcbiAgICAgICAgICovXG4gICAgICAgIHRvTWF0cml4Rm9ybWF0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkIHx8IHFzID09PSAnJykge1xuICAgICAgICAgICAgICAgIHJldHVybiAnOyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodHlwZW9mIHFzID09PSAnc3RyaW5nJyB8fCBxcyBpbnN0YW5jZW9mIFN0cmluZykge1xuICAgICAgICAgICAgICAgIHJldHVybiBxcztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJldHVybkFycmF5ID0gW107XG4gICAgICAgICAgICB2YXIgT1BFUkFUT1JTID0gWyc8JywgJz4nLCAnISddO1xuICAgICAgICAgICAgJC5lYWNoKHFzLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnIHx8ICQuaW5BcnJheSgkLnRyaW0odmFsdWUpLmNoYXJBdCgwKSwgT1BFUkFUT1JTKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSAnPScgKyB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuQXJyYXkucHVzaChrZXkgKyB2YWx1ZSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdmFyIG10cnggPSAnOycgKyByZXR1cm5BcnJheS5qb2luKCc7Jyk7XG4gICAgICAgICAgICByZXR1cm4gbXRyeDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgc3RyaW5ncy9hcnJheXMvb2JqZWN0cyB0byB0eXBlICdhPWImYj1jJ1xuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXNcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRvUXVlcnlGb3JtYXQ6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodHlwZW9mIHFzID09PSAnc3RyaW5nJyB8fCBxcyBpbnN0YW5jZW9mIFN0cmluZykge1xuICAgICAgICAgICAgICAgIHJldHVybiBxcztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJldHVybkFycmF5ID0gW107XG4gICAgICAgICAgICAkLmVhY2gocXMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgaWYgKCQuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZS5qb2luKCcsJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vTW9zdGx5IGZvciBkYXRhIGFwaVxuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuQXJyYXkucHVzaChrZXkgKyAnPScgKyB2YWx1ZSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJldHVybkFycmF5LmpvaW4oJyYnKTtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHN0cmluZ3Mgb2YgdHlwZSAnYT1iJmI9YycgdG8geyBhOmIsIGI6Y31cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ30gcXNcbiAgICAgICAgICogQHJldHVybiB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgcXNUb09iamVjdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCB8fCBxcyA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge307XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBxc0FycmF5ID0gcXMuc3BsaXQoJyYnKTtcbiAgICAgICAgICAgIHZhciByZXR1cm5PYmogPSB7fTtcbiAgICAgICAgICAgICQuZWFjaChxc0FycmF5LCBmdW5jdGlvbiAoaW5kZXgsIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgdmFyIHFLZXkgPSB2YWx1ZS5zcGxpdCgnPScpWzBdO1xuICAgICAgICAgICAgICAgIHZhciBxVmFsID0gdmFsdWUuc3BsaXQoJz0nKVsxXTtcblxuICAgICAgICAgICAgICAgIGlmIChxVmFsLmluZGV4T2YoJywnKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgcVZhbCA9IHFWYWwuc3BsaXQoJywnKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpbcUtleV0gPSBxVmFsO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiByZXR1cm5PYmo7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5vcm1hbGl6ZXMgYW5kIG1lcmdlcyBzdHJpbmdzIG9mIHR5cGUgJ2E9YicsIHsgYjpjfSB0byB7IGE6YiwgYjpjfVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXMxXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxczJcbiAgICAgICAgICogQHJldHVybiB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgbWVyZ2VRUzogZnVuY3Rpb24gKHFzMSwgcXMyKSB7XG4gICAgICAgICAgICB2YXIgb2JqMSA9IHRoaXMucXNUb09iamVjdCh0aGlzLnRvUXVlcnlGb3JtYXQocXMxKSk7XG4gICAgICAgICAgICB2YXIgb2JqMiA9IHRoaXMucXNUb09iamVjdCh0aGlzLnRvUXVlcnlGb3JtYXQocXMyKSk7XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIG9iajEsIG9iajIpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGFkZFRyYWlsaW5nU2xhc2g6IGZ1bmN0aW9uICh1cmwpIHtcbiAgICAgICAgICAgIGlmICghdXJsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuICh1cmwuY2hhckF0KHVybC5sZW5ndGggLSAxKSA9PT0gJy8nKSA/IHVybCA6ICh1cmwgKyAnLycpO1xuICAgICAgICB9XG4gICAgfTtcbn0oKSk7XG5cblxuXG4iLCIvKipcbiAqIFV0aWxpdGllcyBmb3Igd29ya2luZyB3aXRoIHRoZSBydW4gc2VydmljZVxuKi9cbid1c2Ugc3RyaWN0JztcbnZhciBxdXRpbCA9IHJlcXVpcmUoJy4vcXVlcnktdXRpbCcpO1xudmFyIE1BWF9VUkxfTEVOR1RIID0gMjA0ODtcblxubW9kdWxlLmV4cG9ydHMgPSAoZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiByZXR1cm5zIG9wZXJhdGlvbnMgb2YgdGhlIGZvcm0gYFtbb3AxLG9wMl0sIFthcmcxLCBhcmcyXV1gXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdHxBcnJheXxTdHJpbmd9IGBvcGVyYXRpb25zYCBvcGVyYXRpb25zIHRvIHBlcmZvcm1cbiAgICAgICAgICogQHBhcmFtICB7QXJyYXl9IGBhcmdzYCBhcmd1bWVudHMgZm9yIG9wZXJhdGlvblxuICAgICAgICAgKiBAcmV0dXJuIHtTdHJpbmd9ICAgIE1hdHJpeC1mb3JtYXQgcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAgKi9cbiAgICAgICAgbm9ybWFsaXplT3BlcmF0aW9uczogZnVuY3Rpb24gKG9wZXJhdGlvbnMsIGFyZ3MpIHtcbiAgICAgICAgICAgIGlmICghYXJncykge1xuICAgICAgICAgICAgICAgIGFyZ3MgPSBbXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciByZXR1cm5MaXN0ID0ge1xuICAgICAgICAgICAgICAgIG9wczogW10sXG4gICAgICAgICAgICAgICAgYXJnczogW11cbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfY29uY2F0ID0gZnVuY3Rpb24gKGFycikge1xuICAgICAgICAgICAgICAgIHJldHVybiAoYXJyICE9PSBudWxsICYmIGFyciAhPT0gdW5kZWZpbmVkKSA/IFtdLmNvbmNhdChhcnIpIDogW107XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAvL3sgYWRkOiBbMSwyXSwgc3VidHJhY3Q6IFsyLDRdIH1cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplUGxhaW5PYmplY3RzID0gZnVuY3Rpb24gKG9wZXJhdGlvbnMsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJC5lYWNoKG9wZXJhdGlvbnMsIGZ1bmN0aW9uIChvcG4sIGFyZykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wbik7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQoYXJnKSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgLy97IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxXSB9XG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZVN0cnVjdHVyZWRPYmplY3RzID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wZXJhdGlvbi5uYW1lKTtcbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KG9wZXJhdGlvbi5wYXJhbXMpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplT2JqZWN0ID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAoKG9wZXJhdGlvbi5uYW1lKSA/IF9ub3JtYWxpemVTdHJ1Y3R1cmVkT2JqZWN0cyA6IF9ub3JtYWxpemVQbGFpbk9iamVjdHMpKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZUxpdGVyYWxzID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgYXJncywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wZXJhdGlvbik7XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChhcmdzKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplQXJyYXlzID0gZnVuY3Rpb24gKG9wZXJhdGlvbnMsIGFyZywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAkLmVhY2gob3BlcmF0aW9ucywgZnVuY3Rpb24gKGluZGV4LCBvcG4pIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChvcG4pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfbm9ybWFsaXplT2JqZWN0KG9wbiwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfbm9ybWFsaXplTGl0ZXJhbHMob3BuLCBhcmdzW2luZGV4XSwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qob3BlcmF0aW9ucykpIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplT2JqZWN0KG9wZXJhdGlvbnMsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICgkLmlzQXJyYXkob3BlcmF0aW9ucykpIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplQXJyYXlzKG9wZXJhdGlvbnMsIGFyZ3MsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplTGl0ZXJhbHMob3BlcmF0aW9ucywgYXJncywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICB9LFxuXG4gICAgICAgIHNwbGl0R2V0RmFjdG9yeTogZnVuY3Rpb24gKGh0dHBPcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgICAgIHZhciBodHRwID0gdGhpcztcbiAgICAgICAgICAgICAgICB2YXIgZ2V0VmFsdWUgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmFsdWUgPSBvcHRpb25zW25hbWVdIHx8IGh0dHBPcHRpb25zW25hbWVdO1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGdldEZpbmFsVXJsID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdXJsID0gZ2V0VmFsdWUoJ3VybCcsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IHBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlcmUgaXMgZWFzeSAob3Iga25vd24pIHdheSB0byBnZXQgdGhlIGZpbmFsIFVSTCBqcXVlcnkgaXMgZ29pbmcgdG8gc2VuZCBzb1xuICAgICAgICAgICAgICAgICAgICAvLyB3ZSdyZSByZXBsaWNhdGluZyBpdC4gVGhlIHByb2Nlc3MgbWlnaHQgY2hhbmdlIGF0IHNvbWUgcG9pbnQgYnV0IGl0IHByb2JhYmx5IHdpbGwgbm90LlxuICAgICAgICAgICAgICAgICAgICAvLyAxLiBSZW1vdmUgaGFzaFxuICAgICAgICAgICAgICAgICAgICB1cmwgPSB1cmwucmVwbGFjZSgvIy4qJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gQXBwZW5kIHF1ZXJ5IHN0cmluZ1xuICAgICAgICAgICAgICAgICAgICB2YXIgcXVlcnlQYXJhbXMgPSBxdXRpbC50b1F1ZXJ5Rm9ybWF0KGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgcXVlc3Rpb25JZHggPSB1cmwuaW5kZXhPZignPycpO1xuICAgICAgICAgICAgICAgICAgICBpZiAocXVlcnlQYXJhbXMgJiYgcXVlc3Rpb25JZHggPiAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybCArICcmJyArIHF1ZXJ5UGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHF1ZXJ5UGFyYW1zKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsICsgJz8nICsgcXVlcnlQYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybDtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciB1cmwgPSBnZXRGaW5hbFVybChwYXJhbXMpO1xuICAgICAgICAgICAgICAgIC8vIFdlIG11c3Qgc3BsaXQgdGhlIEdFVCBpbiBtdWx0aXBsZSBzaG9ydCBVUkwnc1xuICAgICAgICAgICAgICAgIC8vIFRoZSBvbmx5IHByb3BlcnR5IGFsbG93ZWQgdG8gYmUgc3BsaXQgaXMgXCJpbmNsdWRlXCJcbiAgICAgICAgICAgICAgICBpZiAocGFyYW1zICYmIHBhcmFtcy5pbmNsdWRlICYmIHVybC5sZW5ndGggPiBNQVhfVVJMX0xFTkdUSCkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgcGFyYW1zQ29weSA9ICQuZXh0ZW5kKHRydWUsIHt9LCBwYXJhbXMpO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgcGFyYW1zQ29weS5pbmNsdWRlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgdXJsTm9JbmNsdWRlcyA9IGdldEZpbmFsVXJsKHBhcmFtc0NvcHkpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZGlmZiA9IE1BWF9VUkxfTEVOR1RIIC0gdXJsTm9JbmNsdWRlcy5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIHZhciBvbGRTdWNjZXNzID0gb3B0aW9ucy5zdWNjZXNzIHx8IGh0dHBPcHRpb25zLnN1Y2Nlc3MgfHwgJC5ub29wO1xuICAgICAgICAgICAgICAgICAgICB2YXIgb2xkRXJyb3IgPSBvcHRpb25zLmVycm9yIHx8IGh0dHBPcHRpb25zLmVycm9yIHx8ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgLy8gcmVtb3ZlIHRoZSBvcmlnaW5hbCBzdWNjZXNzIGFuZCBlcnJvciBjYWxsYmFja3NcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5zdWNjZXNzID0gJC5ub29wO1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmVycm9yID0gJC5ub29wO1xuXG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmNsdWRlID0gcGFyYW1zLmluY2x1ZGU7XG4gICAgICAgICAgICAgICAgICAgIHZhciBjdXJySW5jbHVkZXMgPSBbXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGluY2x1ZGVPcHRzID0gW2N1cnJJbmNsdWRlc107XG4gICAgICAgICAgICAgICAgICAgIHZhciBjdXJyTGVuZ3RoID0gJz9pbmNsdWRlPScubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmFyaWFibGUgPSBpbmNsdWRlLnBvcCgpO1xuICAgICAgICAgICAgICAgICAgICB3aGlsZSAodmFyaWFibGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVzZSBhIGdyZWVkeSBhcHByb2FjaCBmb3Igbm93LCBjYW4gYmUgb3B0aW1pemVkIHRvIGJlIHNvbHZlZCBpbiBhIG1vcmVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGVmZmljaWVudCB3YXlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICsgMSBpcyB0aGUgY29tbWFcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjdXJyTGVuZ3RoICsgdmFyaWFibGUubGVuZ3RoICsgMSA8IGRpZmYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJySW5jbHVkZXMucHVzaCh2YXJpYWJsZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCArPSB2YXJpYWJsZS5sZW5ndGggKyAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJySW5jbHVkZXMgPSBbdmFyaWFibGVdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGVPcHRzLnB1c2goY3VyckluY2x1ZGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyTGVuZ3RoID0gJz9pbmNsdWRlPScubGVuZ3RoICsgdmFyaWFibGUubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUgPSBpbmNsdWRlLnBvcCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHZhciByZXFzID0gJC5tYXAoaW5jbHVkZU9wdHMsIGZ1bmN0aW9uIChpbmNsdWRlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVxUGFyYW1zID0gJC5leHRlbmQoe30sIHBhcmFtcywgeyBpbmNsdWRlOiBpbmNsdWRlIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHJlcVBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAkLndoZW4uYXBwbHkoJCwgcmVxcykudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBFYWNoIGFyZ3VtZW50IGFyZSBhcnJheXMgb2YgdGhlIGFyZ3VtZW50cyBvZiBlYWNoIGRvbmUgcmVxdWVzdFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU28gdGhlIGZpcnN0IGFyZ3VtZW50IG9mIHRoZSBmaXJzdCBhcnJheSBvZiBhcmd1bWVudHMgaXMgdGhlIGRhdGFcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc1ZhbGlkID0gYXJndW1lbnRzWzBdICYmIGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaXNWYWxpZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNob3VsZCBuZXZlciBoYXBwZW4uLi5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRFcnJvcigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBkdGQucmVqZWN0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmlyc3RSZXNwb25zZSA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc09iamVjdCA9ICQuaXNQbGFpbk9iamVjdChmaXJzdFJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc1J1bkFQSSA9IChpc09iamVjdCAmJiAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZS52YXJpYWJsZXMpKSB8fCAhaXNPYmplY3Q7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNSdW5BUEkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSB2YXJpYWJsZXMgcHJvcGVydHkgb25seVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgYWdncmVnYXRlUnVuID0gYXJndW1lbnRzWzBdWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVuID0gYXJnc1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZVJ1bi52YXJpYWJsZXMsIHJ1bi52YXJpYWJsZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkU3VjY2VzcyhhZ2dyZWdhdGVSdW4sIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXJyYXkgb2YgcnVuc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBZ3JlZ2F0ZSB2YXJpYWJsZXMgaW4gZWFjaCBydW5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZWRSdW5zID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChhcmd1bWVudHMsIGZ1bmN0aW9uIChpZHgsIGFyZ3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBydW5zID0gYXJnc1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghJC5pc0FycmF5KHJ1bnMpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKHJ1bnMsIGZ1bmN0aW9uIChpZHhSdW4sIHJ1bikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChydW4uaWQgJiYgIWFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuLnZhcmlhYmxlcyA9IHJ1bi52YXJpYWJsZXMgfHwge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0gPSBydW47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChydW4uaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5leHRlbmQodHJ1ZSwgYWdncmVnYXRlZFJ1bnNbcnVuLmlkXS52YXJpYWJsZXMsIHJ1bi52YXJpYWJsZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdHVybiBpdCBpbnRvIGFuIGFycmF5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZWRSdW5zID0gJC5tYXAoYWdncmVnYXRlZFJ1bnMsIGZ1bmN0aW9uIChydW4pIHsgcmV0dXJuIHJ1bjsgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFJ1bnMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoYWdncmVnYXRlZFJ1bnMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlzIHZhcmlhYmxlcyBBUElcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhZ2dyZWdhdGUgdGhlIHJlc3BvbnNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciB2YXJzID0gYXJnc1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5leHRlbmQodHJ1ZSwgYWdncmVnYXRlZFZhcmlhYmxlcywgdmFycyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkU3VjY2VzcyhhZ2dyZWdhdGVkVmFyaWFibGVzLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvbGRFcnJvci5hcHBseShodHRwLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlamVjdC5hcHBseShkdGQsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQocGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfTtcbn0oKSk7XG4iXX0= diff --git a/dist/epicenter.min.js b/dist/epicenter.min.js index f8f0590e..0f6aa7b7 100644 --- a/dist/epicenter.min.js +++ b/dist/epicenter.min.js @@ -17,7 +17,7 @@ var F={util:{},factory:{},transport:{},store:{},service:{},manager:{strategy:{}} }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./api-version.json":5,"./managers/auth-manager":7,"./managers/epicenter-channel-manager":9,"./managers/run-manager":11,"./managers/run-strategies/always-new-strategy":12,"./managers/run-strategies/conditional-creation-strategy":13,"./managers/run-strategies/identity-strategy":14,"./managers/run-strategies/new-if-initialized-strategy":16,"./managers/run-strategies/new-if-missing-strategy":17,"./managers/run-strategies/new-if-persisted-strategy":18,"./managers/scenario-manager":21,"./managers/world-manager":23,"./service/admin-file-service":24,"./service/asset-api-adapter":25,"./service/auth-api-service":26,"./service/channel-service":27,"./service/configuration-service":28,"./service/data-api-service":29,"./service/member-api-adapter":30,"./service/run-api-service":31,"./service/state-api-adapter":32,"./service/url-config-service":33,"./service/user-api-adapter":34,"./service/variables-api-service":35,"./service/world-api-adapter":36,"./store/cookie-store":37,"./store/store-factory":38,"./transport/ajax-http-transport":39,"./transport/http-transport-factory":40,"./util/inherit":41,"./util/make-sequence":42,"./util/query-util":44,"./util/run-util":45}],7:[function(require,module,exports){ -"use strict";function saveSession(userInfo){var serialized=JSON.stringify(userInfo);store.set(EPI_SESSION_KEY,serialized),store.set(EPI_COOKIE_KEY,userInfo.auth_token)}function getSession(){var session=store.get(EPI_SESSION_KEY)||"{}";return JSON.parse(session)}function AuthManager(options){this.options=$.extend(!0,{},defaults,options);var urlConfig=new ConfigService(this.options).get("server");this.options.account||(this.options.account=urlConfig.accountPath),void 0===this.options.project&&(this.options.project=urlConfig.projectPath),store=new StorageFactory(this.options.store),session=getSession(),token=store.get(EPI_COOKIE_KEY)||"",this.authAdapter=new AuthAdapter(this.options,{token:session.auth_token})}var ConfigService=require("../service/configuration-service");var AuthAdapter=require("../service/auth-api-service");var MemberAdapter=require("../service/member-api-adapter");var StorageFactory=require("../store/store-factory");var Buffer=require("buffer").Buffer;var keyNames=require("./key-names");var defaults={store:{synchronous:!0}};var EPI_COOKIE_KEY=keyNames.EPI_COOKIE_KEY;var EPI_SESSION_KEY=keyNames.EPI_SESSION_KEY;var store;var token;var session;var _findUserInGroup=function(members,id){for(var j=0;j1&&groupId){var filteredGroups=$.grep(memberInfo,function(resGroup){return resGroup.groupId===groupId});group=1===filteredGroups.length?filteredGroups[0]:null}if(group){var groupSelection=group.groupId;data.groupSelection[adapterOptions.project]=groupSelection;var sessionInfoWithGroup=$.extend({},sessionInfo,{groupId:group.groupId,groupName:group.name,isFac:"facilitator"===_findUserInGroup(group.members,userInfo.user_id).role});saveSession(sessionInfoWithGroup),outSuccess.apply(this,[data]),$d.resolve(data)}else handleGroupError("This user is associated with more than one group. Please specify a group id to log into and try again",403,data)}).fail($d.reject)};return adapterOptions.success=handleSuccess,adapterOptions.error=function(response){return adapterOptions.account?(adapterOptions.account=null,adapterOptions.error=function(){outError.apply(this,arguments),$d.reject(response)},void _this.authAdapter.login(adapterOptions)):(outError.apply(this,arguments),void $d.reject(response))},this.authAdapter.login(adapterOptions),$d.promise()},logout:function(options){var adapterOptions=$.extend(!0,{token:token},this.options,options);var removeCookieFn=function(response){store.remove(EPI_COOKIE_KEY,adapterOptions),store.remove(EPI_SESSION_KEY,adapterOptions),token=""};return this.authAdapter.logout(adapterOptions).done(removeCookieFn)},getToken:function(options){var httpOptions=$.extend(!0,this.options,options);var $d=$.Deferred();return token?$d.resolve(token):this.login(httpOptions).then($d.resolve),$d.promise()},getUserGroups:function(params,options){var adapterOptions=$.extend(!0,{success:$.noop},this.options,options);var $d=$.Deferred();var outSuccess=adapterOptions.success;adapterOptions.success=function(memberInfo){adapterOptions.project&&(memberInfo=$.grep(memberInfo,function(group){return group.project===adapterOptions.project})),outSuccess.apply(this,[memberInfo]),$d.resolve(memberInfo)};var memberAdapter=new MemberAdapter({token:params.token});return memberAdapter.getGroupsForUser(params,adapterOptions).fail($d.reject),$d.promise()},getCurrentUserSessionInfo:function(options){return getSession(options)}}),module.exports=AuthManager; +"use strict";function saveSession(userInfo,store){var serialized=JSON.stringify(userInfo);store.set(EPI_SESSION_KEY,serialized),store.set(EPI_COOKIE_KEY,userInfo.auth_token)}function getSession(store){var session=store.get(EPI_SESSION_KEY)||"{}";return JSON.parse(session)}function AuthManager(options){this.options=$.extend(!0,{},defaults,options);var urlConfig=new ConfigService(this.options).get("server");this.options.account||(this.options.account=urlConfig.accountPath),void 0===this.options.project&&(this.options.project=urlConfig.projectPath),void 0===this.options.store.root&&this.options.account&&this.options.project&&(this.options.store.root="/app/"+this.options.account+"/"+this.options.project),this.store=new StorageFactory(this.options.store),session=getSession(this.store),token=this.store.get(EPI_COOKIE_KEY)||"",this.authAdapter=new AuthAdapter(this.options,{token:session.auth_token})}var ConfigService=require("../service/configuration-service");var AuthAdapter=require("../service/auth-api-service");var MemberAdapter=require("../service/member-api-adapter");var StorageFactory=require("../store/store-factory");var Buffer=require("buffer").Buffer;var keyNames=require("./key-names");var defaults={store:{synchronous:!0}};var EPI_COOKIE_KEY=keyNames.EPI_COOKIE_KEY;var EPI_SESSION_KEY=keyNames.EPI_SESSION_KEY;var store;var token;var session;var _findUserInGroup=function(members,id){for(var j=0;j1&&groupId){var filteredGroups=$.grep(memberInfo,function(resGroup){return resGroup.groupId===groupId});group=1===filteredGroups.length?filteredGroups[0]:null}if(group){var groupSelection=group.groupId;data.groupSelection[adapterOptions.project]=groupSelection;var sessionInfoWithGroup=$.extend({},sessionInfo,{groupId:group.groupId,groupName:group.name,isFac:"facilitator"===_findUserInGroup(group.members,userInfo.user_id).role});saveSession(sessionInfoWithGroup,_this.store),outSuccess.apply(this,[data]),$d.resolve(data)}else handleGroupError("This user is associated with more than one group. Please specify a group id to log into and try again",403,data)}).fail($d.reject)};return adapterOptions.success=handleSuccess,adapterOptions.error=function(response){return adapterOptions.account?(adapterOptions.account=null,adapterOptions.error=function(){outError.apply(this,arguments),$d.reject(response)},void _this.authAdapter.login(adapterOptions)):(outError.apply(this,arguments),void $d.reject(response))},this.authAdapter.login(adapterOptions),$d.promise()},logout:function(options){var adapterOptions=$.extend(!0,{token:token},this.options,options);var removeCookieFn=function(response){store.remove(EPI_COOKIE_KEY,adapterOptions),store.remove(EPI_SESSION_KEY,adapterOptions),token=""};return this.authAdapter.logout(adapterOptions).done(removeCookieFn)},getToken:function(options){var httpOptions=$.extend(!0,this.options,options);var $d=$.Deferred();return token?$d.resolve(token):this.login(httpOptions).then($d.resolve),$d.promise()},getUserGroups:function(params,options){var adapterOptions=$.extend(!0,{success:$.noop},this.options,options);var $d=$.Deferred();var outSuccess=adapterOptions.success;adapterOptions.success=function(memberInfo){adapterOptions.project&&(memberInfo=$.grep(memberInfo,function(group){return group.project===adapterOptions.project})),outSuccess.apply(this,[memberInfo]),$d.resolve(memberInfo)};var memberAdapter=new MemberAdapter({token:params.token});return memberAdapter.getGroupsForUser(params,adapterOptions).fail($d.reject),$d.promise()},getCurrentUserSessionInfo:function(options){return getSession(this.store,options)}}),module.exports=AuthManager; },{"../service/auth-api-service":26,"../service/configuration-service":28,"../service/member-api-adapter":30,"../store/store-factory":38,"./key-names":10,"buffer":1}],8:[function(require,module,exports){ "use strict";var Channel=require("../service/channel-service");var ChannelManager=function(options){if(!$.cometd)throw new Error("Cometd library not found. Please include epicenter-multiplayer-dependencies.js");if(!options||!options.url)throw new Error("Please provide an url for the cometd server");var defaults={url:"",logLevel:"info",websocketEnabled:!1,shareConnection:!1,channel:{}};var defaultCometOptions=$.extend(!0,{},defaults,options);if(this.currentSubscriptions=[],this.options=defaultCometOptions,defaultCometOptions.shareConnection&&ChannelManager.prototype._cometd)return this.cometd=ChannelManager.prototype._cometd,this;var cometd=new $.Cometd;ChannelManager.prototype._cometd=cometd,cometd.websocketEnabled=defaultCometOptions.websocketEnabled,this.isConnected=!1;var connectionBroken=function(message){$(this).trigger("disconnect",message)};var connectionSucceeded=function(message){$(this).trigger("connect",message)};var me=this;cometd.configure(defaultCometOptions),cometd.addListener("/meta/connect",function(message){var wasConnected=this.isConnected;this.isConnected=message.successful===!0,!wasConnected&&this.isConnected?connectionSucceeded.call(this,message):wasConnected&&!this.isConnected&&connectionBroken.call(this,message)}.bind(this)),cometd.addListener("/meta/disconnect",connectionBroken),cometd.addListener("/meta/handshake",function(message){message.successful&&cometd.batch(function(){$(me.currentSubscriptions).each(function(index,subs){cometd.resubscribe(subs)})})}),cometd.addListener("/meta/subscribe",function(message){$(me).trigger("subscribe",message)}),cometd.addListener("/meta/unsubscribe",function(message){$(me).trigger("unsubscribe",message)}),cometd.addListener("/meta/publish",function(message){$(me).trigger("publish",message)}),cometd.addListener("/meta/unsuccessful",function(message){$(me).trigger("error",message)}),cometd.handshake(),this.cometd=cometd};ChannelManager.prototype=$.extend(ChannelManager.prototype,{getChannel:function(options){options&&!$.isPlainObject(options)&&(options={base:options});var defaults={transport:this.cometd};var channel=new Channel($.extend(!0,{},this.options.channel,defaults,options));var subs=channel.subscribe;channel.subscribe=function(){var subid=subs.apply(channel,arguments);return this.currentSubscriptions=this.currentSubscriptions.concat(subid),subid}.bind(this);var unsubs=channel.unsubscribe;return channel.unsubscribe=function(){var removed=unsubs.apply(channel,arguments);for(var i=0;i\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && url.length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = '?include='.length;\n var variable = include.pop();\n while (variable) {\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + variable.length + 1 < diff) {\n currIncludes.push(variable);\n currLength += variable.length + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + variable.length;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ##File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n // config || (config = configService.get());\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || store.get('epicenter.token') || '',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: '',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {String} `folderType` One of Model|Static|Node\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, folderType, options) {\n var path = folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ##Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * ##Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: '',\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n domain: 'forio.com',\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ##Authentication API Service\n *\n * The Authentication API Service provides methods for logging in and logging out. On login, this service creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n * auth.logout();\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n /**\n * Logs user out from specified accounts.\n * Epicenter logout is not implemented yet, added a dummy promise that gets automatically resolved.\n *\n * **Example**\n *\n * auth.logout();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ##World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n $.extend(params, _pick(serviceOptions, ['account', 'project', 'group']));\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ##State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ##User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ##Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: '',\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar keyNames = require('../managers/key-names');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n var session = JSON.parse(store.get(keyNames.EPI_SESSION_KEY) || '{}');\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get(keyNames.EPI_COOKIE_KEY) || '',\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: session.userId,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n var serviceOptions = $.extend(true, {}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.forio.com'\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n\n document.cookie = encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookieReg = new RegExp('(?:(?:^|.*;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$');\n var val = document.cookie.replace(cookieReg, '$1');\n val = decodeURIComponent(val) || null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n\n document.cookie = encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var aKeys = document.cookie.replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* ####Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar ConfigService = require('../service/configuration-service');\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar StorageFactory = require('../store/store-factory');\nvar Buffer = require('buffer').Buffer;\nvar keyNames = require('./key-names');\n\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY;\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar store;\nvar token;\nvar session;\n\nfunction saveSession(userInfo) {\n var serialized = JSON.stringify(userInfo);\n store.set(EPI_SESSION_KEY, serialized);\n\n //jshint camelcase: false\n //jscs:disable\n store.set(EPI_COOKIE_KEY, userInfo.auth_token);\n}\n\nfunction getSession() {\n var session = store.get(EPI_SESSION_KEY) || '{}';\n return JSON.parse(session);\n}\n\nfunction AuthManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n var urlConfig = new ConfigService(this.options).get('server');\n if (!this.options.account) {\n this.options.account = urlConfig.accountPath;\n }\n\n // null might specified to disable project filtering\n if (this.options.project === undefined) {\n this.options.project = urlConfig.projectPath;\n }\n\n store = new StorageFactory(this.options.store);\n session = getSession();\n token = store.get(EPI_COOKIE_KEY) || '';\n //jshint camelcase: false\n //jscs:disable\n this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token });\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(memberInfo, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n var groupSelection = group.groupId;\n data.groupSelection[adapterOptions.project] = groupSelection;\n var sessionInfoWithGroup = $.extend({}, sessionInfo, {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n });\n saveSession(sessionInfoWithGroup);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n }).fail($d.reject);\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var adapterOptions = $.extend(true, { token: token }, this.options, options);\n\n var removeCookieFn = function (response) {\n store.remove(EPI_COOKIE_KEY, adapterOptions);\n store.remove(EPI_SESSION_KEY, adapterOptions);\n token = '';\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) { \n * console.log('My token is ', token); \n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = $.extend(true, this.options, options);\n\n var $d = $.Deferred();\n if (token) {\n $d.resolve(token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) { \n * for (var i=0; i < groups.length; i++) \n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = $.extend(true, { success: $.noop }, this.options, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option. \n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return getSession(options);\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `server` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `server.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `server.project` Epicenter project id.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\n\nvar AuthManager = require('./auth-manager');\n\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n var userInfo = session.getCurrentUserSessionInfo();\n\n var defaults = {\n account: userInfo.account,\n project: userInfo.project,\n };\n var defaultCometOptions = $.extend(true, {}, defaults, userInfo, options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getDataChannel('survey-responses');\n * gc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionStore = require('../../store/store-factory');\nvar classFrom = require('../../util/inherit');\nvar UrlService = require('../../service/url-config-service');\nvar AuthManager = require('../auth-manager');\n\nvar sessionStore = new SessionStore({});\nvar urlService = new UrlService();\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, path) {\n if (!path) {\n if (!urlService.isLocalhost()) {\n path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/');\n // make sure we don't get consecuteive '/' so we have a valid path for the session\n path = path.replace(/\\/{2,}/g,'/');\n } else {\n path = '';\n }\n }\n // set the seesionKey for the run\n sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path });\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.options.path);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession);\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","'use strict';\n\nmodule.exports = {\n EPI_COOKIE_KEY: 'epicenter.project.token',\n EPI_SESSION_KEY: 'epicenter.user.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","'use strict';\n\nvar Channel = require('../service/channel-service');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n }\n };\n var defaultCometOptions = $.extend(true, {}, defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake();\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('is-array')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\nBuffer.poolSize = 8192 // not used by this implementation\n\nvar rootParent = {}\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property\n * on objects.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\nfunction typedArraySupport () {\n function Bar () {}\n try {\n var arr = new Uint8Array(1)\n arr.foo = function () { return 42 }\n arr.constructor = Bar\n return arr.foo() === 42 && // typed array instances can be augmented\n arr.constructor === Bar && // constructor can be set\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\n/**\n * Class: Buffer\n * =============\n *\n * The Buffer constructor returns instances of `Uint8Array` that are augmented\n * with function properties for all the node `Buffer` API functions. We use\n * `Uint8Array` so that square bracket notation works as expected -- it returns\n * a single octet.\n *\n * By augmenting the instances, we can avoid modifying the `Uint8Array`\n * prototype.\n */\nfunction Buffer (arg) {\n if (!(this instanceof Buffer)) {\n // Avoid going through an ArgumentsAdaptorTrampoline in the common case.\n if (arguments.length > 1) return new Buffer(arg, arguments[1])\n return new Buffer(arg)\n }\n\n this.length = 0\n this.parent = undefined\n\n // Common case.\n if (typeof arg === 'number') {\n return fromNumber(this, arg)\n }\n\n // Slightly less common case.\n if (typeof arg === 'string') {\n return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')\n }\n\n // Unusual.\n return fromObject(this, arg)\n}\n\nfunction fromNumber (that, length) {\n that = allocate(that, length < 0 ? 0 : checked(length) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < length; i++) {\n that[i] = 0\n }\n }\n return that\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'\n\n // Assumption: byteLength() return value is always < kMaxLength.\n var length = byteLength(string, encoding) | 0\n that = allocate(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromObject (that, object) {\n if (Buffer.isBuffer(object)) return fromBuffer(that, object)\n\n if (isArray(object)) return fromArray(that, object)\n\n if (object == null) {\n throw new TypeError('must start with number, buffer, array or string')\n }\n\n if (typeof ArrayBuffer !== 'undefined') {\n if (object.buffer instanceof ArrayBuffer) {\n return fromTypedArray(that, object)\n }\n if (object instanceof ArrayBuffer) {\n return fromArrayBuffer(that, object)\n }\n }\n\n if (object.length) return fromArrayLike(that, object)\n\n return fromJsonObject(that, object)\n}\n\nfunction fromBuffer (that, buffer) {\n var length = checked(buffer.length) | 0\n that = allocate(that, length)\n buffer.copy(that, 0, 0, length)\n return that\n}\n\nfunction fromArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Duplicate of fromArray() to keep fromArray() monomorphic.\nfunction fromTypedArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n // Truncating the elements is probably not what people expect from typed\n // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior\n // of the old Buffer constructor.\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n array.byteLength\n that = Buffer._augment(new Uint8Array(array))\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromTypedArray(that, new Uint8Array(array))\n }\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.\n// Returns a zero-length buffer for inputs that don't conform to the spec.\nfunction fromJsonObject (that, object) {\n var array\n var length = 0\n\n if (object.type === 'Buffer' && isArray(object.data)) {\n array = object.data\n length = checked(array.length) | 0\n }\n that = allocate(that, length)\n\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n}\n\nfunction allocate (that, length) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = Buffer._augment(new Uint8Array(length))\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that.length = length\n that._isBuffer = true\n }\n\n var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1\n if (fromPool) that.parent = rootParent\n\n return that\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (subject, encoding) {\n if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)\n\n var buf = new Buffer(subject, encoding)\n delete buf.parent\n return buf\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n var i = 0\n var len = Math.min(x, y)\n while (i < len) {\n if (a[i] !== b[i]) break\n\n ++i\n }\n\n if (i !== len) {\n x = a[i]\n y = b[i]\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')\n\n if (list.length === 0) {\n return new Buffer(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; i++) {\n length += list[i].length\n }\n }\n\n var buf = new Buffer(length)\n var pos = 0\n for (i = 0; i < list.length; i++) {\n var item = list[i]\n item.copy(buf, pos)\n pos += item.length\n }\n return buf\n}\n\nfunction byteLength (string, encoding) {\n if (typeof string !== 'string') string = '' + string\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n // Deprecated\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\n// pre-set for values that may exist in the future\nBuffer.prototype.length = undefined\nBuffer.prototype.parent = undefined\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n start = start | 0\n end = end === undefined || end === Infinity ? this.length : end | 0\n\n if (!encoding) encoding = 'utf8'\n if (start < 0) start = 0\n if (end > this.length) end = this.length\n if (end <= start) return ''\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return 0\n return Buffer.compare(this, b)\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset) {\n if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff\n else if (byteOffset < -0x80000000) byteOffset = -0x80000000\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n if (val.length === 0) return -1 // special case: looking for empty string always fails\n return String.prototype.indexOf.call(this, val, byteOffset)\n }\n if (Buffer.isBuffer(val)) {\n return arrayIndexOf(this, val, byteOffset)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset)\n }\n\n function arrayIndexOf (arr, val, byteOffset) {\n var foundIndex = -1\n for (var i = 0; byteOffset + i < arr.length; i++) {\n if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex\n } else {\n foundIndex = -1\n }\n }\n return -1\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\n// `get` is deprecated\nBuffer.prototype.get = function get (offset) {\n console.log('.get() is deprecated. Access using array indexes instead.')\n return this.readUInt8(offset)\n}\n\n// `set` is deprecated\nBuffer.prototype.set = function set (v, offset) {\n console.log('.set() is deprecated. Access using array indexes instead.')\n return this.writeUInt8(v, offset)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; i++) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) throw new Error('Invalid hex string')\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n var swap = encoding\n encoding = offset\n offset = length | 0\n length = swap\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; i++) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = Buffer._augment(this.subarray(start, end))\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; i++) {\n newBuf[i] = this[i + start]\n }\n }\n\n if (newBuf.length) newBuf.parent = this.parent || this\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n if (offset < 0) throw new RangeError('index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; i--) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; i++) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n target._set(this.subarray(start, start + len), targetStart)\n }\n\n return len\n}\n\n// fill(value, start=0, end=buffer.length)\nBuffer.prototype.fill = function fill (value, start, end) {\n if (!value) value = 0\n if (!start) start = 0\n if (!end) end = this.length\n\n if (end < start) throw new RangeError('end < start')\n\n // Fill 0 bytes; we're done\n if (end === start) return\n if (this.length === 0) return\n\n if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')\n if (end < 0 || end > this.length) throw new RangeError('end out of bounds')\n\n var i\n if (typeof value === 'number') {\n for (i = start; i < end; i++) {\n this[i] = value\n }\n } else {\n var bytes = utf8ToBytes(value.toString())\n var len = bytes.length\n for (i = start; i < end; i++) {\n this[i] = bytes[i % len]\n }\n }\n\n return this\n}\n\n/**\n * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.\n * Added in Node 0.12. Only available in browsers that support ArrayBuffer.\n */\nBuffer.prototype.toArrayBuffer = function toArrayBuffer () {\n if (typeof Uint8Array !== 'undefined') {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n return (new Buffer(this)).buffer\n } else {\n var buf = new Uint8Array(this.length)\n for (var i = 0, len = buf.length; i < len; i += 1) {\n buf[i] = this[i]\n }\n return buf.buffer\n }\n } else {\n throw new TypeError('Buffer.toArrayBuffer not supported in this browser')\n }\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar BP = Buffer.prototype\n\n/**\n * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods\n */\nBuffer._augment = function _augment (arr) {\n arr.constructor = Buffer\n arr._isBuffer = true\n\n // save reference to original Uint8Array set method before overwriting\n arr._set = arr.set\n\n // deprecated\n arr.get = BP.get\n arr.set = BP.set\n\n arr.write = BP.write\n arr.toString = BP.toString\n arr.toLocaleString = BP.toString\n arr.toJSON = BP.toJSON\n arr.equals = BP.equals\n arr.compare = BP.compare\n arr.indexOf = BP.indexOf\n arr.copy = BP.copy\n arr.slice = BP.slice\n arr.readUIntLE = BP.readUIntLE\n arr.readUIntBE = BP.readUIntBE\n arr.readUInt8 = BP.readUInt8\n arr.readUInt16LE = BP.readUInt16LE\n arr.readUInt16BE = BP.readUInt16BE\n arr.readUInt32LE = BP.readUInt32LE\n arr.readUInt32BE = BP.readUInt32BE\n arr.readIntLE = BP.readIntLE\n arr.readIntBE = BP.readIntBE\n arr.readInt8 = BP.readInt8\n arr.readInt16LE = BP.readInt16LE\n arr.readInt16BE = BP.readInt16BE\n arr.readInt32LE = BP.readInt32LE\n arr.readInt32BE = BP.readInt32BE\n arr.readFloatLE = BP.readFloatLE\n arr.readFloatBE = BP.readFloatBE\n arr.readDoubleLE = BP.readDoubleLE\n arr.readDoubleBE = BP.readDoubleBE\n arr.writeUInt8 = BP.writeUInt8\n arr.writeUIntLE = BP.writeUIntLE\n arr.writeUIntBE = BP.writeUIntBE\n arr.writeUInt16LE = BP.writeUInt16LE\n arr.writeUInt16BE = BP.writeUInt16BE\n arr.writeUInt32LE = BP.writeUInt32LE\n arr.writeUInt32BE = BP.writeUInt32BE\n arr.writeIntLE = BP.writeIntLE\n arr.writeIntBE = BP.writeIntBE\n arr.writeInt8 = BP.writeInt8\n arr.writeInt16LE = BP.writeInt16LE\n arr.writeInt16BE = BP.writeInt16BE\n arr.writeInt32LE = BP.writeInt32LE\n arr.writeInt32BE = BP.writeInt32BE\n arr.writeFloatLE = BP.writeFloatLE\n arr.writeFloatBE = BP.writeFloatBE\n arr.writeDoubleLE = BP.writeDoubleLE\n arr.writeDoubleBE = BP.writeDoubleBE\n arr.fill = BP.fill\n arr.inspect = BP.inspect\n arr.toArrayBuffer = BP.toArrayBuffer\n\n return arr\n}\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; i++) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; i++) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n;(function (exports) {\n\t'use strict';\n\n var Arr = (typeof Uint8Array !== 'undefined')\n ? Uint8Array\n : Array\n\n\tvar PLUS = '+'.charCodeAt(0)\n\tvar SLASH = '/'.charCodeAt(0)\n\tvar NUMBER = '0'.charCodeAt(0)\n\tvar LOWER = 'a'.charCodeAt(0)\n\tvar UPPER = 'A'.charCodeAt(0)\n\tvar PLUS_URL_SAFE = '-'.charCodeAt(0)\n\tvar SLASH_URL_SAFE = '_'.charCodeAt(0)\n\n\tfunction decode (elt) {\n\t\tvar code = elt.charCodeAt(0)\n\t\tif (code === PLUS ||\n\t\t code === PLUS_URL_SAFE)\n\t\t\treturn 62 // '+'\n\t\tif (code === SLASH ||\n\t\t code === SLASH_URL_SAFE)\n\t\t\treturn 63 // '/'\n\t\tif (code < NUMBER)\n\t\t\treturn -1 //no match\n\t\tif (code < NUMBER + 10)\n\t\t\treturn code - NUMBER + 26 + 26\n\t\tif (code < UPPER + 26)\n\t\t\treturn code - UPPER\n\t\tif (code < LOWER + 26)\n\t\t\treturn code - LOWER + 26\n\t}\n\n\tfunction b64ToByteArray (b64) {\n\t\tvar i, j, l, tmp, placeHolders, arr\n\n\t\tif (b64.length % 4 > 0) {\n\t\t\tthrow new Error('Invalid string. Length must be a multiple of 4')\n\t\t}\n\n\t\t// the number of equal signs (place holders)\n\t\t// if there are two placeholders, than the two characters before it\n\t\t// represent one byte\n\t\t// if there is only one, then the three characters before it represent 2 bytes\n\t\t// this is just a cheap hack to not do indexOf twice\n\t\tvar len = b64.length\n\t\tplaceHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0\n\n\t\t// base64 is 4/3 + up to two characters of the original data\n\t\tarr = new Arr(b64.length * 3 / 4 - placeHolders)\n\n\t\t// if there are placeholders, only get up to the last complete 4 chars\n\t\tl = placeHolders > 0 ? b64.length - 4 : b64.length\n\n\t\tvar L = 0\n\n\t\tfunction push (v) {\n\t\t\tarr[L++] = v\n\t\t}\n\n\t\tfor (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))\n\t\t\tpush((tmp & 0xFF0000) >> 16)\n\t\t\tpush((tmp & 0xFF00) >> 8)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\tif (placeHolders === 2) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)\n\t\t\tpush(tmp & 0xFF)\n\t\t} else if (placeHolders === 1) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)\n\t\t\tpush((tmp >> 8) & 0xFF)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\treturn arr\n\t}\n\n\tfunction uint8ToBase64 (uint8) {\n\t\tvar i,\n\t\t\textraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes\n\t\t\toutput = \"\",\n\t\t\ttemp, length\n\n\t\tfunction encode (num) {\n\t\t\treturn lookup.charAt(num)\n\t\t}\n\n\t\tfunction tripletToBase64 (num) {\n\t\t\treturn encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)\n\t\t}\n\n\t\t// go through the array every three bytes, we'll deal with trailing stuff later\n\t\tfor (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n\t\t\ttemp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n\t\t\toutput += tripletToBase64(temp)\n\t\t}\n\n\t\t// pad the end with zeros, but make sure to not forget the extra bytes\n\t\tswitch (extraBytes) {\n\t\t\tcase 1:\n\t\t\t\ttemp = uint8[uint8.length - 1]\n\t\t\t\toutput += encode(temp >> 2)\n\t\t\t\toutput += encode((temp << 4) & 0x3F)\n\t\t\t\toutput += '=='\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\ttemp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])\n\t\t\t\toutput += encode(temp >> 10)\n\t\t\t\toutput += encode((temp >> 4) & 0x3F)\n\t\t\t\toutput += encode((temp << 2) & 0x3F)\n\t\t\t\toutput += '='\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn output\n\t}\n\n\texports.toByteArray = b64ToByteArray\n\texports.fromByteArray = uint8ToBase64\n}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))\n","\n/**\n * isArray\n */\n\nvar isArray = Array.isArray;\n\n/**\n * toString\n */\n\nvar str = Object.prototype.toString;\n\n/**\n * Whether or not the given `val`\n * is an array.\n *\n * example:\n *\n * isArray([]);\n * // > true\n * isArray(arguments);\n * // > false\n * isArray('');\n * // > false\n *\n * @param {mixed} val\n * @return {bool}\n */\n\nmodule.exports = isArray || function (val) {\n return !! val && '[object Array]' == str.call(val);\n};\n"]} \ No newline at end of file +{"version":3,"sources":["node_modules/grunt-browserify/node_modules/browserify/node_modules/browser-pack/_prelude.js","src/api-version.json","src/app.js","src/util/query-util.js","src/util/make-sequence.js","src/util/run-util.js","src/util/inherit.js","src/transport/http-transport-factory.js","src/transport/ajax-http-transport.js","src/service/url-config-service.js","src/service/configuration-service.js","src/service/run-api-service.js","src/service/admin-file-service.js","src/service/variables-api-service.js","src/service/data-api-service.js","src/service/auth-api-service.js","src/service/world-api-adapter.js","src/service/state-api-adapter.js","src/service/user-api-adapter.js","src/service/member-api-adapter.js","src/service/asset-api-adapter.js","src/store/cookie-store.js","src/store/store-factory.js","src/managers/scenario-manager.js","src/managers/run-manager.js","src/managers/auth-manager.js","src/managers/world-manager.js","src/managers/epicenter-channel-manager.js","src/service/channel-service.js","src/managers/run-strategies/always-new-strategy.js","src/managers/run-strategies/conditional-creation-strategy.js","src/managers/run-strategies/identity-strategy.js","src/managers/run-strategies/new-if-missing-strategy.js","src/managers/run-strategies/new-if-persisted-strategy.js","src/managers/run-strategies/new-if-initialized-strategy.js","src/util/object-util.js","src/managers/key-names.js","src/managers/special-operations.js","src/managers/channel-manager.js","src/managers/run-strategies/strategies-map.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/index.js","src/managers/run-strategies/multiplayer-strategy.js","src/managers/run-strategies/persistent-single-player-strategy.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/ieee754/index.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/base64-js/lib/b64.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/is-array/index.js"],"names":["F","util","factory","transport","store","service","manager","strategy","query","require","makeSequence","run","classFrom","Transport","Ajax","URL","Config","Run","File","Variables","Data","Auth","World","State","User","Member","Asset","Cookie","Store","ScenarioManager","RunManager","AuthManager","WorldManager","identity","ChannelManager","Channel","version","api","global","module","exports","toMatrixFormat","qs","undefined","String","returnArray","OPERATORS","$","each","key","value","inArray","trim","charAt","push","mtrx","join","toQueryFormat","isArray","isPlainObject","JSON","stringify","result","qsToObject","qsArray","split","returnObj","index","qKey","qVal","indexOf","mergeQS","qs1","qs2","obj1","this","obj2","extend","addTrailingSlash","url","length","_w","val","then","p","Deferred","resolve","promise","seq","next","cur","list","splice","Array","prototype","slice","apply","arguments","seed","fail","MakeSeq","obj","res","__calls","original","fn","start","_this","funcMaker","bind","args","Function","concat","prop","qutil","MAX_URL_LENGTH","normalizeOperations","operations","returnList","ops","_concat","arr","_normalizePlainObjects","opn","arg","_normalizeStructuredObjects","operation","name","params","_normalizeObject","_normalizeLiterals","_normalizeArrays","splitGetFactory","httpOptions","options","http","getValue","getFinalUrl","data","replace","queryParams","questionIdx","include","dtd","paramsCopy","urlNoIncludes","diff","oldSuccess","success","noop","oldError","error","currIncludes","includeOpts","currLength","variable","pop","reqs","map","reqParams","get","when","isValid","reject","firstResponse","isObject","isRunAPI","variables","aggregateRun","idx","aggregatedRuns","runs","idxRun","id","aggregatedVariables","vars","inherit","C","P","__super","constructor","dest","call","current","j","base","props","staticProps","parent","child","hasOwnProperty","qutils","config","defaults","contentType","headers","statusCode",404,"parameterParser","xhrFields","withCredentials","transportOptions","d","isFunction","connect","method","connectOptions","type","ALLOWED_TO_BE_FUNCTIONS","logLevel","console","log","oldSuccessFn","response","ajaxStatus","ajaxReq","beforeSend","xhr","settings","requestUrl","ajax","publicAPI","ajaxOptions","splitGet","post","patch","put","delete","delimiter","head","epiVersion","API_PROTOCOL","HOST_API_MAPPING","forio.com","foriodev.com","publicExports","protocol","host","window","location","appPath","path","pathname","accountPath","accnt","projectPath","prj","versionPath","isLocalhost","getAPIPath","PROJECT_APIS","apiPath","urlService","serviceOptions","server","setEnv","env","property","set","ConfigService","StorageFactory","rutil","_pick","TransportFactory","VariablesService","synchronous","token","account","project","filter","autoRestore","urlConfig","getFilterURL","addAutoRestoreHeader","isFilterRunId","autorestoreOpts","X-AutoRestore","Authorization","setFilterOrThrowError","Error","publicAsyncAPI","create","createOptions","runApiParams","model","outputModifier","load","runID","filters","save","attributes","do","opsArgs","postOptions","prms","serial","opParams","me","$d","doSingleOp","op","shift","parallel","queue","i","done","publicSyncAPI","getCurrentConfig","vs","runService","getContents","filePath","folderType","getURL","attrs","root","domain","q","saveAs","remove","keys","userName","password","login","resp","status","statusMessage","postParams","logout","apiBase","assignmentEndpoint","apiEndpoint","projectEndpoint","group","setIdFilterOrThrowError","validateModelOrThrowError","worldApiParams","update","whitelist","updateOptions","deleteOptions","updateConfig","getOptions","getWorldsForUser","userId","worldId","addUsers","users","u","updateUser","user","patchOptions","removeUser","getCurrentRunId","getCurrentWorldForUser","groupName","worlds","sort","a","b","Date","lastModified","currentWorld","deleteRun","newRunForWorld","currentRunOptions","autoAssign","opt","maxUsers","getProjectSettings","parseRunIdOrError","runId","replay","replayOptions","action","clone","toQFilter","toIdFilters","getFilters","threshold","getById","groupId","getFinalParams","patchUserActiveField","active","getGroupsForUser","isString","objParams","getParms","getGroupDetails","makeUserActive","makeUserInactive","keyNames","session","parse","EPI_SESSION_KEY","EPI_COOKIE_KEY","scope","fullUrl","processData","assetApiParams","scopeConfig","validateFilename","filename","validateUrlParams","partKeys","buildUrl","parts","upload","toLowerCase","FormData","urlOptions","getServiceOptions","files","fullPathFiles","file","assetUrl","setOptions","document","cookie","encodeURIComponent","cookieReg","RegExp","decodeURIComponent","remOptions","destroy","aKeys","nIdx","cookieKey","RunService","validFilter","saved","getRuns","loadVariables","meta","_getService","archive","getRun","patchRunService","patched","orig","reservedOps","Object","specialOperations","StrategyCtor","strategiesMap","reset","runServiceOptions","saveSession","userInfo","serialized","auth_token","getSession","authAdapter","AuthAdapter","MemberAdapter","Buffer","_findUserInGroup","members","adapterOptions","outSuccess","outError","decodeToken","encoded","decode","atob","toString","handleGroupError","message","statusText","handleSuccess","access_token","userGroupOpts","getUserGroups","user_id","memberInfo","auth","userGroups","groupSelection","sessionInfo","filteredGroups","grep","resGroup","sessionInfoWithGroup","isFac","role","removeCookieFn","getToken","memberAdapter","getCurrentUserSessionInfo","buildStrategy","worldApi","WorldApi","world","_auth","getCurrentWorld","getCurrentRun","getAndRestoreLatestRun","currentWorldId","runOpts","rm","curUserId","curGroupName","getFromSettingsOrSessionOrError","sessionKeyName","EpicenterChannelManager","defaultCometOptions","urlOpts","getGroupChannel","baseTopic","getChannel","getWorldChannel","worldid","getUserChannel","userid","getPresenceChannel","channel","lastPingTime","PING_INTERVAL","subscribe","notification","incomingUserId","trigger","online","valueOf","setInterval","publish","now","getDataChannel","collection","oldsubs","topic","callback","context","callbackWithCleanData","payload","subType","date","actualData","topicResolver","channelOptions","makeName","channelName","newName","topics","subscriptionIds","opts","batch","returnObjs","warn","unsubscribe","on","event","off","ConditionalStrategy","Strategy","createIf","setRunInSession","sessionKey","sessionStore","makeSeq","Base","SessionStore","UrlService","STRATEGY_SESSION_KEY","condition","runOptions","runOptionsWithScope","userSession","freshlyCreated","runSession","_loadAndCheck","shouldCreate","msg","getResponseHeader","initialized","cometd","websocketEnabled","shareConnection","currentSubscriptions","_cometd","Cometd","isConnected","connectionBroken","connectionSucceeded","configure","addListener","wasConnected","successful","subs","resubscribe","handshake","subid","unsubs","removed","new-if-initialized","new-if-persisted","new-if-missing","always-new","multiplayer","persistent-single-player","none","typedArraySupport","Bar","Uint8Array","foo","subarray","byteLength","e","kMaxLength","TYPED_ARRAY_SUPPORT","fromNumber","fromString","fromObject","that","allocate","checked","string","encoding","write","object","isBuffer","fromBuffer","fromArray","TypeError","ArrayBuffer","buffer","fromTypedArray","fromArrayBuffer","fromArrayLike","fromJsonObject","copy","array","_augment","__proto__","_isBuffer","fromPool","poolSize","rootParent","RangeError","SlowBuffer","subject","buf","len","loweredCase","utf8ToBytes","base64ToBytes","slowToString","end","Infinity","hexSlice","utf8Slice","asciiSlice","binarySlice","base64Slice","utf16leSlice","hexWrite","offset","Number","remaining","strLen","parsed","parseInt","substr","isNaN","utf8Write","blitBuffer","asciiWrite","asciiToBytes","binaryWrite","base64Write","ucs2Write","utf16leToBytes","base64","fromByteArray","Math","min","firstByte","codePoint","bytesPerSequence","secondByte","thirdByte","fourthByte","tempCodePoint","decodeCodePointsArray","codePoints","MAX_ARGUMENTS_LENGTH","fromCharCode","ret","out","toHex","bytes","checkOffset","ext","checkInt","max","objectWriteUInt16","littleEndian","objectWriteUInt32","checkIEEE754","writeFloat","noAssert","ieee754","writeDouble","base64clean","str","stringtrim","INVALID_BASE64_RE","n","units","leadSurrogate","charCodeAt","byteArray","c","hi","lo","toByteArray","src","dst","INSPECT_MAX_BYTES","compare","x","y","isEncoding","pos","item","equals","inspect","match","byteOffset","arrayIndexOf","foundIndex","readUInt8","v","writeUInt8","isFinite","swap","toJSON","_arr","newBuf","sliceLen","readUIntLE","mul","readUIntBE","readUInt16LE","readUInt16BE","readUInt32LE","readUInt32BE","readIntLE","pow","readIntBE","readInt8","readInt16LE","readInt16BE","readInt32LE","readInt32BE","readFloatLE","read","readFloatBE","readDoubleLE","readDoubleBE","writeUIntLE","writeUIntBE","floor","writeUInt16LE","writeUInt16BE","writeUInt32LE","writeUInt32BE","writeIntLE","limit","sub","writeIntBE","writeInt8","writeInt16LE","writeInt16BE","writeInt32LE","writeInt32BE","writeFloatLE","writeFloatBE","writeDoubleLE","writeDoubleBE","target","targetStart","_set","fill","toArrayBuffer","BP","toLocaleString","IdentityStrategy","WorldApiAdapter","_loadRun","loadRunFromWorld","serverError","StateApi","_store","stateApi","_restoreRun","_getAllRuns","user.id","scope.group","dateComp","latestRun","shouldReplay","isLE","mLen","nBytes","m","eLen","eMax","eBias","nBits","s","NaN","rt","abs","LN2","lookup","elt","code","PLUS","PLUS_URL_SAFE","SLASH","SLASH_URL_SAFE","NUMBER","UPPER","LOWER","b64ToByteArray","b64","L","l","tmp","placeHolders","Arr","uint8ToBase64","uint8","encode","num","tripletToBase64","temp","extraBytes","output","base64js"],"mappings":"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","file":"bundle.js","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && url.length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = '?include='.length;\n var variable = include.pop();\n while (variable) {\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + variable.length + 1 < diff) {\n currIncludes.push(variable);\n currLength += variable.length + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + variable.length;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ##File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n // config || (config = configService.get());\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || store.get('epicenter.token') || '',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: '',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {String} `folderType` One of Model|Static|Node\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, folderType, options) {\n var path = folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ##Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * ##Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: '',\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n domain: 'forio.com',\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ##Authentication API Service\n *\n * The Authentication API Service provides methods for logging in and logging out. On login, this service creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n * auth.logout();\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n /**\n * Logs user out from specified accounts.\n * Epicenter logout is not implemented yet, added a dummy promise that gets automatically resolved.\n *\n * **Example**\n *\n * auth.logout();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ##World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n $.extend(params, _pick(serviceOptions, ['account', 'project', 'group']));\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ##State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ##User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ##Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: '',\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar keyNames = require('../managers/key-names');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n var session = JSON.parse(store.get(keyNames.EPI_SESSION_KEY) || '{}');\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get(keyNames.EPI_COOKIE_KEY) || '',\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: session.userId,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n var serviceOptions = $.extend(true, {}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.forio.com'\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n\n document.cookie = encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookieReg = new RegExp('(?:(?:^|.*;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$');\n var val = document.cookie.replace(cookieReg, '$1');\n val = decodeURIComponent(val) || null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n\n document.cookie = encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var aKeys = document.cookie.replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* ####Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar ConfigService = require('../service/configuration-service');\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar StorageFactory = require('../store/store-factory');\nvar Buffer = require('buffer').Buffer;\nvar keyNames = require('./key-names');\n\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY;\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar store;\nvar token;\nvar session;\n\nfunction saveSession(userInfo, store) {\n var serialized = JSON.stringify(userInfo);\n store.set(EPI_SESSION_KEY, serialized);\n\n //jshint camelcase: false\n //jscs:disable\n store.set(EPI_COOKIE_KEY, userInfo.auth_token);\n}\n\nfunction getSession(store) {\n var session = store.get(EPI_SESSION_KEY) || '{}';\n return JSON.parse(session);\n}\n\nfunction AuthManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n var urlConfig = new ConfigService(this.options).get('server');\n if (!this.options.account) {\n this.options.account = urlConfig.accountPath;\n }\n\n // null might specified to disable project filtering\n if (this.options.project === undefined) {\n this.options.project = urlConfig.projectPath;\n }\n\n if (this.options.store.root === undefined && this.options.account && this.options.project) {\n this.options.store.root = '/app/' + this.options.account + '/' + this.options.project;\n }\n\n this.store = new StorageFactory(this.options.store);\n session = getSession(this.store);\n token = this.store.get(EPI_COOKIE_KEY) || '';\n //jshint camelcase: false\n //jscs:disable\n this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token });\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(memberInfo, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n var groupSelection = group.groupId;\n data.groupSelection[adapterOptions.project] = groupSelection;\n var sessionInfoWithGroup = $.extend({}, sessionInfo, {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n });\n saveSession(sessionInfoWithGroup, _this.store);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n }).fail($d.reject);\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var adapterOptions = $.extend(true, { token: token }, this.options, options);\n\n var removeCookieFn = function (response) {\n store.remove(EPI_COOKIE_KEY, adapterOptions);\n store.remove(EPI_SESSION_KEY, adapterOptions);\n token = '';\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = $.extend(true, this.options, options);\n\n var $d = $.Deferred();\n if (token) {\n $d.resolve(token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = $.extend(true, { success: $.noop }, this.options, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return getSession(this.store, options);\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `server` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `server.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `server.project` Epicenter project id.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\n\nvar AuthManager = require('./auth-manager');\n\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n var userInfo = session.getCurrentUserSessionInfo();\n\n var defaults = {\n account: userInfo.account,\n project: userInfo.project,\n };\n var defaultCometOptions = $.extend(true, {}, defaults, userInfo, options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getDataChannel('survey-responses');\n * gc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionStore = require('../../store/store-factory');\nvar classFrom = require('../../util/inherit');\nvar UrlService = require('../../service/url-config-service');\nvar AuthManager = require('../auth-manager');\n\nvar sessionStore = new SessionStore({});\nvar urlService = new UrlService();\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, path) {\n if (!path) {\n if (!urlService.isLocalhost()) {\n path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/');\n // make sure we don't get consecuteive '/' so we have a valid path for the session\n path = path.replace(/\\/{2,}/g,'/');\n } else {\n path = '';\n }\n }\n // set the seesionKey for the run\n sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path });\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.options.path);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession);\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","'use strict';\n\nmodule.exports = {\n EPI_COOKIE_KEY: 'epicenter.project.token',\n EPI_SESSION_KEY: 'epicenter.user.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","'use strict';\n\nvar Channel = require('../service/channel-service');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n }\n };\n var defaultCometOptions = $.extend(true, {}, defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake();\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('is-array')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\nBuffer.poolSize = 8192 // not used by this implementation\n\nvar rootParent = {}\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property\n * on objects.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\nfunction typedArraySupport () {\n function Bar () {}\n try {\n var arr = new Uint8Array(1)\n arr.foo = function () { return 42 }\n arr.constructor = Bar\n return arr.foo() === 42 && // typed array instances can be augmented\n arr.constructor === Bar && // constructor can be set\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\n/**\n * Class: Buffer\n * =============\n *\n * The Buffer constructor returns instances of `Uint8Array` that are augmented\n * with function properties for all the node `Buffer` API functions. We use\n * `Uint8Array` so that square bracket notation works as expected -- it returns\n * a single octet.\n *\n * By augmenting the instances, we can avoid modifying the `Uint8Array`\n * prototype.\n */\nfunction Buffer (arg) {\n if (!(this instanceof Buffer)) {\n // Avoid going through an ArgumentsAdaptorTrampoline in the common case.\n if (arguments.length > 1) return new Buffer(arg, arguments[1])\n return new Buffer(arg)\n }\n\n this.length = 0\n this.parent = undefined\n\n // Common case.\n if (typeof arg === 'number') {\n return fromNumber(this, arg)\n }\n\n // Slightly less common case.\n if (typeof arg === 'string') {\n return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')\n }\n\n // Unusual.\n return fromObject(this, arg)\n}\n\nfunction fromNumber (that, length) {\n that = allocate(that, length < 0 ? 0 : checked(length) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < length; i++) {\n that[i] = 0\n }\n }\n return that\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'\n\n // Assumption: byteLength() return value is always < kMaxLength.\n var length = byteLength(string, encoding) | 0\n that = allocate(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromObject (that, object) {\n if (Buffer.isBuffer(object)) return fromBuffer(that, object)\n\n if (isArray(object)) return fromArray(that, object)\n\n if (object == null) {\n throw new TypeError('must start with number, buffer, array or string')\n }\n\n if (typeof ArrayBuffer !== 'undefined') {\n if (object.buffer instanceof ArrayBuffer) {\n return fromTypedArray(that, object)\n }\n if (object instanceof ArrayBuffer) {\n return fromArrayBuffer(that, object)\n }\n }\n\n if (object.length) return fromArrayLike(that, object)\n\n return fromJsonObject(that, object)\n}\n\nfunction fromBuffer (that, buffer) {\n var length = checked(buffer.length) | 0\n that = allocate(that, length)\n buffer.copy(that, 0, 0, length)\n return that\n}\n\nfunction fromArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Duplicate of fromArray() to keep fromArray() monomorphic.\nfunction fromTypedArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n // Truncating the elements is probably not what people expect from typed\n // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior\n // of the old Buffer constructor.\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n array.byteLength\n that = Buffer._augment(new Uint8Array(array))\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromTypedArray(that, new Uint8Array(array))\n }\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.\n// Returns a zero-length buffer for inputs that don't conform to the spec.\nfunction fromJsonObject (that, object) {\n var array\n var length = 0\n\n if (object.type === 'Buffer' && isArray(object.data)) {\n array = object.data\n length = checked(array.length) | 0\n }\n that = allocate(that, length)\n\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n}\n\nfunction allocate (that, length) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = Buffer._augment(new Uint8Array(length))\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that.length = length\n that._isBuffer = true\n }\n\n var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1\n if (fromPool) that.parent = rootParent\n\n return that\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (subject, encoding) {\n if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)\n\n var buf = new Buffer(subject, encoding)\n delete buf.parent\n return buf\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n var i = 0\n var len = Math.min(x, y)\n while (i < len) {\n if (a[i] !== b[i]) break\n\n ++i\n }\n\n if (i !== len) {\n x = a[i]\n y = b[i]\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')\n\n if (list.length === 0) {\n return new Buffer(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; i++) {\n length += list[i].length\n }\n }\n\n var buf = new Buffer(length)\n var pos = 0\n for (i = 0; i < list.length; i++) {\n var item = list[i]\n item.copy(buf, pos)\n pos += item.length\n }\n return buf\n}\n\nfunction byteLength (string, encoding) {\n if (typeof string !== 'string') string = '' + string\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n // Deprecated\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\n// pre-set for values that may exist in the future\nBuffer.prototype.length = undefined\nBuffer.prototype.parent = undefined\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n start = start | 0\n end = end === undefined || end === Infinity ? this.length : end | 0\n\n if (!encoding) encoding = 'utf8'\n if (start < 0) start = 0\n if (end > this.length) end = this.length\n if (end <= start) return ''\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return 0\n return Buffer.compare(this, b)\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset) {\n if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff\n else if (byteOffset < -0x80000000) byteOffset = -0x80000000\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n if (val.length === 0) return -1 // special case: looking for empty string always fails\n return String.prototype.indexOf.call(this, val, byteOffset)\n }\n if (Buffer.isBuffer(val)) {\n return arrayIndexOf(this, val, byteOffset)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset)\n }\n\n function arrayIndexOf (arr, val, byteOffset) {\n var foundIndex = -1\n for (var i = 0; byteOffset + i < arr.length; i++) {\n if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex\n } else {\n foundIndex = -1\n }\n }\n return -1\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\n// `get` is deprecated\nBuffer.prototype.get = function get (offset) {\n console.log('.get() is deprecated. Access using array indexes instead.')\n return this.readUInt8(offset)\n}\n\n// `set` is deprecated\nBuffer.prototype.set = function set (v, offset) {\n console.log('.set() is deprecated. Access using array indexes instead.')\n return this.writeUInt8(v, offset)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; i++) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) throw new Error('Invalid hex string')\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n var swap = encoding\n encoding = offset\n offset = length | 0\n length = swap\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; i++) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = Buffer._augment(this.subarray(start, end))\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; i++) {\n newBuf[i] = this[i + start]\n }\n }\n\n if (newBuf.length) newBuf.parent = this.parent || this\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n if (offset < 0) throw new RangeError('index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; i--) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; i++) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n target._set(this.subarray(start, start + len), targetStart)\n }\n\n return len\n}\n\n// fill(value, start=0, end=buffer.length)\nBuffer.prototype.fill = function fill (value, start, end) {\n if (!value) value = 0\n if (!start) start = 0\n if (!end) end = this.length\n\n if (end < start) throw new RangeError('end < start')\n\n // Fill 0 bytes; we're done\n if (end === start) return\n if (this.length === 0) return\n\n if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')\n if (end < 0 || end > this.length) throw new RangeError('end out of bounds')\n\n var i\n if (typeof value === 'number') {\n for (i = start; i < end; i++) {\n this[i] = value\n }\n } else {\n var bytes = utf8ToBytes(value.toString())\n var len = bytes.length\n for (i = start; i < end; i++) {\n this[i] = bytes[i % len]\n }\n }\n\n return this\n}\n\n/**\n * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.\n * Added in Node 0.12. Only available in browsers that support ArrayBuffer.\n */\nBuffer.prototype.toArrayBuffer = function toArrayBuffer () {\n if (typeof Uint8Array !== 'undefined') {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n return (new Buffer(this)).buffer\n } else {\n var buf = new Uint8Array(this.length)\n for (var i = 0, len = buf.length; i < len; i += 1) {\n buf[i] = this[i]\n }\n return buf.buffer\n }\n } else {\n throw new TypeError('Buffer.toArrayBuffer not supported in this browser')\n }\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar BP = Buffer.prototype\n\n/**\n * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods\n */\nBuffer._augment = function _augment (arr) {\n arr.constructor = Buffer\n arr._isBuffer = true\n\n // save reference to original Uint8Array set method before overwriting\n arr._set = arr.set\n\n // deprecated\n arr.get = BP.get\n arr.set = BP.set\n\n arr.write = BP.write\n arr.toString = BP.toString\n arr.toLocaleString = BP.toString\n arr.toJSON = BP.toJSON\n arr.equals = BP.equals\n arr.compare = BP.compare\n arr.indexOf = BP.indexOf\n arr.copy = BP.copy\n arr.slice = BP.slice\n arr.readUIntLE = BP.readUIntLE\n arr.readUIntBE = BP.readUIntBE\n arr.readUInt8 = BP.readUInt8\n arr.readUInt16LE = BP.readUInt16LE\n arr.readUInt16BE = BP.readUInt16BE\n arr.readUInt32LE = BP.readUInt32LE\n arr.readUInt32BE = BP.readUInt32BE\n arr.readIntLE = BP.readIntLE\n arr.readIntBE = BP.readIntBE\n arr.readInt8 = BP.readInt8\n arr.readInt16LE = BP.readInt16LE\n arr.readInt16BE = BP.readInt16BE\n arr.readInt32LE = BP.readInt32LE\n arr.readInt32BE = BP.readInt32BE\n arr.readFloatLE = BP.readFloatLE\n arr.readFloatBE = BP.readFloatBE\n arr.readDoubleLE = BP.readDoubleLE\n arr.readDoubleBE = BP.readDoubleBE\n arr.writeUInt8 = BP.writeUInt8\n arr.writeUIntLE = BP.writeUIntLE\n arr.writeUIntBE = BP.writeUIntBE\n arr.writeUInt16LE = BP.writeUInt16LE\n arr.writeUInt16BE = BP.writeUInt16BE\n arr.writeUInt32LE = BP.writeUInt32LE\n arr.writeUInt32BE = BP.writeUInt32BE\n arr.writeIntLE = BP.writeIntLE\n arr.writeIntBE = BP.writeIntBE\n arr.writeInt8 = BP.writeInt8\n arr.writeInt16LE = BP.writeInt16LE\n arr.writeInt16BE = BP.writeInt16BE\n arr.writeInt32LE = BP.writeInt32LE\n arr.writeInt32BE = BP.writeInt32BE\n arr.writeFloatLE = BP.writeFloatLE\n arr.writeFloatBE = BP.writeFloatBE\n arr.writeDoubleLE = BP.writeDoubleLE\n arr.writeDoubleBE = BP.writeDoubleBE\n arr.fill = BP.fill\n arr.inspect = BP.inspect\n arr.toArrayBuffer = BP.toArrayBuffer\n\n return arr\n}\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; i++) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; i++) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n;(function (exports) {\n\t'use strict';\n\n var Arr = (typeof Uint8Array !== 'undefined')\n ? Uint8Array\n : Array\n\n\tvar PLUS = '+'.charCodeAt(0)\n\tvar SLASH = '/'.charCodeAt(0)\n\tvar NUMBER = '0'.charCodeAt(0)\n\tvar LOWER = 'a'.charCodeAt(0)\n\tvar UPPER = 'A'.charCodeAt(0)\n\tvar PLUS_URL_SAFE = '-'.charCodeAt(0)\n\tvar SLASH_URL_SAFE = '_'.charCodeAt(0)\n\n\tfunction decode (elt) {\n\t\tvar code = elt.charCodeAt(0)\n\t\tif (code === PLUS ||\n\t\t code === PLUS_URL_SAFE)\n\t\t\treturn 62 // '+'\n\t\tif (code === SLASH ||\n\t\t code === SLASH_URL_SAFE)\n\t\t\treturn 63 // '/'\n\t\tif (code < NUMBER)\n\t\t\treturn -1 //no match\n\t\tif (code < NUMBER + 10)\n\t\t\treturn code - NUMBER + 26 + 26\n\t\tif (code < UPPER + 26)\n\t\t\treturn code - UPPER\n\t\tif (code < LOWER + 26)\n\t\t\treturn code - LOWER + 26\n\t}\n\n\tfunction b64ToByteArray (b64) {\n\t\tvar i, j, l, tmp, placeHolders, arr\n\n\t\tif (b64.length % 4 > 0) {\n\t\t\tthrow new Error('Invalid string. Length must be a multiple of 4')\n\t\t}\n\n\t\t// the number of equal signs (place holders)\n\t\t// if there are two placeholders, than the two characters before it\n\t\t// represent one byte\n\t\t// if there is only one, then the three characters before it represent 2 bytes\n\t\t// this is just a cheap hack to not do indexOf twice\n\t\tvar len = b64.length\n\t\tplaceHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0\n\n\t\t// base64 is 4/3 + up to two characters of the original data\n\t\tarr = new Arr(b64.length * 3 / 4 - placeHolders)\n\n\t\t// if there are placeholders, only get up to the last complete 4 chars\n\t\tl = placeHolders > 0 ? b64.length - 4 : b64.length\n\n\t\tvar L = 0\n\n\t\tfunction push (v) {\n\t\t\tarr[L++] = v\n\t\t}\n\n\t\tfor (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))\n\t\t\tpush((tmp & 0xFF0000) >> 16)\n\t\t\tpush((tmp & 0xFF00) >> 8)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\tif (placeHolders === 2) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)\n\t\t\tpush(tmp & 0xFF)\n\t\t} else if (placeHolders === 1) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)\n\t\t\tpush((tmp >> 8) & 0xFF)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\treturn arr\n\t}\n\n\tfunction uint8ToBase64 (uint8) {\n\t\tvar i,\n\t\t\textraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes\n\t\t\toutput = \"\",\n\t\t\ttemp, length\n\n\t\tfunction encode (num) {\n\t\t\treturn lookup.charAt(num)\n\t\t}\n\n\t\tfunction tripletToBase64 (num) {\n\t\t\treturn encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)\n\t\t}\n\n\t\t// go through the array every three bytes, we'll deal with trailing stuff later\n\t\tfor (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n\t\t\ttemp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n\t\t\toutput += tripletToBase64(temp)\n\t\t}\n\n\t\t// pad the end with zeros, but make sure to not forget the extra bytes\n\t\tswitch (extraBytes) {\n\t\t\tcase 1:\n\t\t\t\ttemp = uint8[uint8.length - 1]\n\t\t\t\toutput += encode(temp >> 2)\n\t\t\t\toutput += encode((temp << 4) & 0x3F)\n\t\t\t\toutput += '=='\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\ttemp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])\n\t\t\t\toutput += encode(temp >> 10)\n\t\t\t\toutput += encode((temp >> 4) & 0x3F)\n\t\t\t\toutput += encode((temp << 2) & 0x3F)\n\t\t\t\toutput += '='\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn output\n\t}\n\n\texports.toByteArray = b64ToByteArray\n\texports.fromByteArray = uint8ToBase64\n}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))\n","\n/**\n * isArray\n */\n\nvar isArray = Array.isArray;\n\n/**\n * toString\n */\n\nvar str = Object.prototype.toString;\n\n/**\n * Whether or not the given `val`\n * is an array.\n *\n * example:\n *\n * isArray([]);\n * // > true\n * isArray(arguments);\n * // > false\n * isArray('');\n * // > false\n *\n * @param {mixed} val\n * @return {bool}\n */\n\nmodule.exports = isArray || function (val) {\n return !! val && '[object Array]' == str.call(val);\n};\n"]} \ No newline at end of file From 1334083f58d82755e38a17e2e71244bf70fcb2af Mon Sep 17 00:00:00 2001 From: john zhang Date: Fri, 26 Feb 2016 15:59:32 -0800 Subject: [PATCH 06/14] update cookie directory on login isntead of constructor --- src/managers/auth-manager.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/managers/auth-manager.js b/src/managers/auth-manager.js index fbfde1de..e19a77bf 100644 --- a/src/managers/auth-manager.js +++ b/src/managers/auth-manager.js @@ -79,10 +79,6 @@ function AuthManager(options) { this.options.project = urlConfig.projectPath; } - if (this.options.store.root === undefined && this.options.account && this.options.project) { - this.options.store.root = '/app/' + this.options.account + '/' + this.options.project; - } - this.store = new StorageFactory(this.options.store); session = getSession(this.store); token = this.store.get(EPI_COOKIE_KEY) || ''; @@ -146,6 +142,10 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { var outError = adapterOptions.error; var groupId = adapterOptions.groupId; + if (this.options.store.root === undefined && this.options.account && this.options.project) { + this.options.store.root = '/app/' + this.options.account + '/' + this.options.project; + } + var decodeToken = function (token) { var encoded = token.split('.')[1]; while (encoded.length % 4 !== 0) { From a80df08836b7ae2db7ada7b36280623b3efc1498 Mon Sep 17 00:00:00 2001 From: john zhang Date: Fri, 26 Feb 2016 16:10:04 -0800 Subject: [PATCH 07/14] fix tests and include account/project infor from options --- src/managers/auth-manager.js | 7 +++++-- tests/spec/test-auth-manager.js | 14 +++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/managers/auth-manager.js b/src/managers/auth-manager.js index e19a77bf..e842a5d4 100644 --- a/src/managers/auth-manager.js +++ b/src/managers/auth-manager.js @@ -142,8 +142,11 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { var outError = adapterOptions.error; var groupId = adapterOptions.groupId; - if (this.options.store.root === undefined && this.options.account && this.options.project) { - this.options.store.root = '/app/' + this.options.account + '/' + this.options.project; + var accountName = (options && options.account) ? options.account : this.options.account; + var projectName = (options && options.project) ? options.project : this.options.project; + + if (this.options.store.root === undefined && accountName && projectName) { + this.store.serviceOptions.root = '/app/' + accountName + '/' + projectName; } var decodeToken = function (token) { diff --git a/tests/spec/test-auth-manager.js b/tests/spec/test-auth-manager.js index b8dc10d1..19e70722 100644 --- a/tests/spec/test-auth-manager.js +++ b/tests/spec/test-auth-manager.js @@ -47,13 +47,25 @@ // TODO: Create some test, find a way for the fake server to auto respond synchronously inside a respond callback describe('#setting cookies', function () { - it ('creates cookie with the correct path name', function () { + it ('creates cookie with the correct path name when passing in account info in consructor', function () { var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName' }); + am.login(); am.store.serviceOptions.root.should.equal('/app/accountName/projectName'); }); }); + describe('#setting cookies', function () { + it ('creates cookie with the correct path name when passing in account info in login', function () { + var am = new F.manager.AuthManager() + am.login({ + account: 'accountName', + project: 'projectName' + }); + am.store.serviceOptions.root.should.equal('/app/accountName/projectName'); + }); + }); + }); }()); From c52bc309bbe23ddbf02ed8fd9c7f983baf739221 Mon Sep 17 00:00:00 2001 From: john zhang Date: Fri, 26 Feb 2016 16:11:00 -0800 Subject: [PATCH 08/14] add ; --- tests/spec/test-auth-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/spec/test-auth-manager.js b/tests/spec/test-auth-manager.js index 19e70722..49e40d47 100644 --- a/tests/spec/test-auth-manager.js +++ b/tests/spec/test-auth-manager.js @@ -58,7 +58,7 @@ }); describe('#setting cookies', function () { it ('creates cookie with the correct path name when passing in account info in login', function () { - var am = new F.manager.AuthManager() + var am = new F.manager.AuthManager(); am.login({ account: 'accountName', project: 'projectName' From 69efdef97ddc63c0e582c05df68dc0c8203d84a6 Mon Sep 17 00:00:00 2001 From: Molly Jones Date: Fri, 26 Feb 2016 16:13:28 -0800 Subject: [PATCH 09/14] build dist components for epicenter-1590 for testing --- dist/epicenter.js | 13 ++++++++----- dist/epicenter.min.js | 2 +- dist/epicenter.min.js.map | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/dist/epicenter.js b/dist/epicenter.js index a41dc3f0..572cad94 100644 --- a/dist/epicenter.js +++ b/dist/epicenter.js @@ -1949,10 +1949,6 @@ function AuthManager(options) { this.options.project = urlConfig.projectPath; } - if (this.options.store.root === undefined && this.options.account && this.options.project) { - this.options.store.root = '/app/' + this.options.account + '/' + this.options.project; - } - this.store = new StorageFactory(this.options.store); session = getSession(this.store); token = this.store.get(EPI_COOKIE_KEY) || ''; @@ -2016,6 +2012,13 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { var outError = adapterOptions.error; var groupId = adapterOptions.groupId; + var accountName = (options && options.account) ? options.account : this.options.account; + var projectName = (options && options.project) ? options.project : this.options.project; + + if (this.options.store.root === undefined && accountName && projectName) { + this.store.serviceOptions.root = '/app/' + accountName + '/' + projectName; + } + var decodeToken = function (token) { var encoded = token.split('.')[1]; while (encoded.length % 4 !== 0) { @@ -7446,4 +7449,4 @@ module.exports = (function () { }()); },{"./query-util":44}]},{},[6]) -//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL25vZGVfbW9kdWxlcy9pZWVlNzU0L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvaXMtYXJyYXkvaW5kZXguanMiLCJzcmMvYXBpLXZlcnNpb24uanNvbiIsInNyYy9hcHAuanMiLCJzcmMvbWFuYWdlcnMvYXV0aC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2NoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2tleS1uYW1lcy5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9hbHdheXMtbmV3LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2lkZW50aXR5LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL211bHRpcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcC5qcyIsInNyYy9tYW5hZ2Vycy9zY2VuYXJpby1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3NwZWNpYWwtb3BlcmF0aW9ucy5qcyIsInNyYy9tYW5hZ2Vycy93b3JsZC1tYW5hZ2VyLmpzIiwic3JjL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyLmpzIiwic3JjL3N0b3JlL2Nvb2tpZS1zdG9yZS5qcyIsInNyYy9zdG9yZS9zdG9yZS1mYWN0b3J5LmpzIiwic3JjL3RyYW5zcG9ydC9hamF4LWh0dHAtdHJhbnNwb3J0LmpzIiwic3JjL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5LmpzIiwic3JjL3V0aWwvaW5oZXJpdC5qcyIsInNyYy91dGlsL21ha2Utc2VxdWVuY2UuanMiLCJzcmMvdXRpbC9vYmplY3QtdXRpbC5qcyIsInNyYy91dGlsL3F1ZXJ5LXV0aWwuanMiLCJzcmMvdXRpbC9ydW4tdXRpbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN4Z0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2V0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMVRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0UUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25LQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzdUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLyohXG4gKiBUaGUgYnVmZmVyIG1vZHVsZSBmcm9tIG5vZGUuanMsIGZvciB0aGUgYnJvd3Nlci5cbiAqXG4gKiBAYXV0aG9yICAgRmVyb3NzIEFib3VraGFkaWplaCA8ZmVyb3NzQGZlcm9zcy5vcmc+IDxodHRwOi8vZmVyb3NzLm9yZz5cbiAqIEBsaWNlbnNlICBNSVRcbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tcHJvdG8gKi9cblxudmFyIGJhc2U2NCA9IHJlcXVpcmUoJ2Jhc2U2NC1qcycpXG52YXIgaWVlZTc1NCA9IHJlcXVpcmUoJ2llZWU3NTQnKVxudmFyIGlzQXJyYXkgPSByZXF1aXJlKCdpcy1hcnJheScpXG5cbmV4cG9ydHMuQnVmZmVyID0gQnVmZmVyXG5leHBvcnRzLlNsb3dCdWZmZXIgPSBTbG93QnVmZmVyXG5leHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTID0gNTBcbkJ1ZmZlci5wb29sU2l6ZSA9IDgxOTIgLy8gbm90IHVzZWQgYnkgdGhpcyBpbXBsZW1lbnRhdGlvblxuXG52YXIgcm9vdFBhcmVudCA9IHt9XG5cbi8qKlxuICogSWYgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYDpcbiAqICAgPT09IHRydWUgICAgVXNlIFVpbnQ4QXJyYXkgaW1wbGVtZW50YXRpb24gKGZhc3Rlc3QpXG4gKiAgID09PSBmYWxzZSAgIFVzZSBPYmplY3QgaW1wbGVtZW50YXRpb24gKG1vc3QgY29tcGF0aWJsZSwgZXZlbiBJRTYpXG4gKlxuICogQnJvd3NlcnMgdGhhdCBzdXBwb3J0IHR5cGVkIGFycmF5cyBhcmUgSUUgMTArLCBGaXJlZm94IDQrLCBDaHJvbWUgNyssIFNhZmFyaSA1LjErLFxuICogT3BlcmEgMTEuNissIGlPUyA0LjIrLlxuICpcbiAqIER1ZSB0byB2YXJpb3VzIGJyb3dzZXIgYnVncywgc29tZXRpbWVzIHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24gd2lsbCBiZSB1c2VkIGV2ZW5cbiAqIHdoZW4gdGhlIGJyb3dzZXIgc3VwcG9ydHMgdHlwZWQgYXJyYXlzLlxuICpcbiAqIE5vdGU6XG4gKlxuICogICAtIEZpcmVmb3ggNC0yOSBsYWNrcyBzdXBwb3J0IGZvciBhZGRpbmcgbmV3IHByb3BlcnRpZXMgdG8gYFVpbnQ4QXJyYXlgIGluc3RhbmNlcyxcbiAqICAgICBTZWU6IGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTY5NTQzOC5cbiAqXG4gKiAgIC0gU2FmYXJpIDUtNyBsYWNrcyBzdXBwb3J0IGZvciBjaGFuZ2luZyB0aGUgYE9iamVjdC5wcm90b3R5cGUuY29uc3RydWN0b3JgIHByb3BlcnR5XG4gKiAgICAgb24gb2JqZWN0cy5cbiAqXG4gKiAgIC0gQ2hyb21lIDktMTAgaXMgbWlzc2luZyB0aGUgYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbi5cbiAqXG4gKiAgIC0gSUUxMCBoYXMgYSBicm9rZW4gYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGFycmF5cyBvZlxuICogICAgIGluY29ycmVjdCBsZW5ndGggaW4gc29tZSBzaXR1YXRpb25zLlxuXG4gKiBXZSBkZXRlY3QgdGhlc2UgYnVnZ3kgYnJvd3NlcnMgYW5kIHNldCBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgIHRvIGBmYWxzZWAgc28gdGhleVxuICogZ2V0IHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24sIHdoaWNoIGlzIHNsb3dlciBidXQgYmVoYXZlcyBjb3JyZWN0bHkuXG4gKi9cbkJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUID0gZ2xvYmFsLlRZUEVEX0FSUkFZX1NVUFBPUlQgIT09IHVuZGVmaW5lZFxuICA/IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gIDogdHlwZWRBcnJheVN1cHBvcnQoKVxuXG5mdW5jdGlvbiB0eXBlZEFycmF5U3VwcG9ydCAoKSB7XG4gIGZ1bmN0aW9uIEJhciAoKSB7fVxuICB0cnkge1xuICAgIHZhciBhcnIgPSBuZXcgVWludDhBcnJheSgxKVxuICAgIGFyci5mb28gPSBmdW5jdGlvbiAoKSB7IHJldHVybiA0MiB9XG4gICAgYXJyLmNvbnN0cnVjdG9yID0gQmFyXG4gICAgcmV0dXJuIGFyci5mb28oKSA9PT0gNDIgJiYgLy8gdHlwZWQgYXJyYXkgaW5zdGFuY2VzIGNhbiBiZSBhdWdtZW50ZWRcbiAgICAgICAgYXJyLmNvbnN0cnVjdG9yID09PSBCYXIgJiYgLy8gY29uc3RydWN0b3IgY2FuIGJlIHNldFxuICAgICAgICB0eXBlb2YgYXJyLnN1YmFycmF5ID09PSAnZnVuY3Rpb24nICYmIC8vIGNocm9tZSA5LTEwIGxhY2sgYHN1YmFycmF5YFxuICAgICAgICBhcnIuc3ViYXJyYXkoMSwgMSkuYnl0ZUxlbmd0aCA9PT0gMCAvLyBpZTEwIGhhcyBicm9rZW4gYHN1YmFycmF5YFxuICB9IGNhdGNoIChlKSB7XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuZnVuY3Rpb24ga01heExlbmd0aCAoKSB7XG4gIHJldHVybiBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVFxuICAgID8gMHg3ZmZmZmZmZlxuICAgIDogMHgzZmZmZmZmZlxufVxuXG4vKipcbiAqIENsYXNzOiBCdWZmZXJcbiAqID09PT09PT09PT09PT1cbiAqXG4gKiBUaGUgQnVmZmVyIGNvbnN0cnVjdG9yIHJldHVybnMgaW5zdGFuY2VzIG9mIGBVaW50OEFycmF5YCB0aGF0IGFyZSBhdWdtZW50ZWRcbiAqIHdpdGggZnVuY3Rpb24gcHJvcGVydGllcyBmb3IgYWxsIHRoZSBub2RlIGBCdWZmZXJgIEFQSSBmdW5jdGlvbnMuIFdlIHVzZVxuICogYFVpbnQ4QXJyYXlgIHNvIHRoYXQgc3F1YXJlIGJyYWNrZXQgbm90YXRpb24gd29ya3MgYXMgZXhwZWN0ZWQgLS0gaXQgcmV0dXJuc1xuICogYSBzaW5nbGUgb2N0ZXQuXG4gKlxuICogQnkgYXVnbWVudGluZyB0aGUgaW5zdGFuY2VzLCB3ZSBjYW4gYXZvaWQgbW9kaWZ5aW5nIHRoZSBgVWludDhBcnJheWBcbiAqIHByb3RvdHlwZS5cbiAqL1xuZnVuY3Rpb24gQnVmZmVyIChhcmcpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIEJ1ZmZlcikpIHtcbiAgICAvLyBBdm9pZCBnb2luZyB0aHJvdWdoIGFuIEFyZ3VtZW50c0FkYXB0b3JUcmFtcG9saW5lIGluIHRoZSBjb21tb24gY2FzZS5cbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIHJldHVybiBuZXcgQnVmZmVyKGFyZywgYXJndW1lbnRzWzFdKVxuICAgIHJldHVybiBuZXcgQnVmZmVyKGFyZylcbiAgfVxuXG4gIHRoaXMubGVuZ3RoID0gMFxuICB0aGlzLnBhcmVudCA9IHVuZGVmaW5lZFxuXG4gIC8vIENvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ251bWJlcicpIHtcbiAgICByZXR1cm4gZnJvbU51bWJlcih0aGlzLCBhcmcpXG4gIH1cblxuICAvLyBTbGlnaHRseSBsZXNzIGNvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gZnJvbVN0cmluZyh0aGlzLCBhcmcsIGFyZ3VtZW50cy5sZW5ndGggPiAxID8gYXJndW1lbnRzWzFdIDogJ3V0ZjgnKVxuICB9XG5cbiAgLy8gVW51c3VhbC5cbiAgcmV0dXJuIGZyb21PYmplY3QodGhpcywgYXJnKVxufVxuXG5mdW5jdGlvbiBmcm9tTnVtYmVyICh0aGF0LCBsZW5ndGgpIHtcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aCA8IDAgPyAwIDogY2hlY2tlZChsZW5ndGgpIHwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHRoYXRbaV0gPSAwXG4gICAgfVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21TdHJpbmcgKHRoYXQsIHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBlbmNvZGluZyAhPT0gJ3N0cmluZycgfHwgZW5jb2RpbmcgPT09ICcnKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIC8vIEFzc3VtcHRpb246IGJ5dGVMZW5ndGgoKSByZXR1cm4gdmFsdWUgaXMgYWx3YXlzIDwga01heExlbmd0aC5cbiAgdmFyIGxlbmd0aCA9IGJ5dGVMZW5ndGgoc3RyaW5nLCBlbmNvZGluZykgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG5cbiAgdGhhdC53cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihvYmplY3QpKSByZXR1cm4gZnJvbUJ1ZmZlcih0aGF0LCBvYmplY3QpXG5cbiAgaWYgKGlzQXJyYXkob2JqZWN0KSkgcmV0dXJuIGZyb21BcnJheSh0aGF0LCBvYmplY3QpXG5cbiAgaWYgKG9iamVjdCA9PSBudWxsKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignbXVzdCBzdGFydCB3aXRoIG51bWJlciwgYnVmZmVyLCBhcnJheSBvciBzdHJpbmcnKVxuICB9XG5cbiAgaWYgKHR5cGVvZiBBcnJheUJ1ZmZlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAob2JqZWN0LmJ1ZmZlciBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgICByZXR1cm4gZnJvbVR5cGVkQXJyYXkodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgICBpZiAob2JqZWN0IGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICAgIHJldHVybiBmcm9tQXJyYXlCdWZmZXIodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgfVxuXG4gIGlmIChvYmplY3QubGVuZ3RoKSByZXR1cm4gZnJvbUFycmF5TGlrZSh0aGF0LCBvYmplY3QpXG5cbiAgcmV0dXJuIGZyb21Kc29uT2JqZWN0KHRoYXQsIG9iamVjdClcbn1cblxuZnVuY3Rpb24gZnJvbUJ1ZmZlciAodGhhdCwgYnVmZmVyKSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGJ1ZmZlci5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICBidWZmZXIuY29weSh0aGF0LCAwLCAwLCBsZW5ndGgpXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheSAodGhhdCwgYXJyYXkpIHtcbiAgdmFyIGxlbmd0aCA9IGNoZWNrZWQoYXJyYXkubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbi8vIER1cGxpY2F0ZSBvZiBmcm9tQXJyYXkoKSB0byBrZWVwIGZyb21BcnJheSgpIG1vbm9tb3JwaGljLlxuZnVuY3Rpb24gZnJvbVR5cGVkQXJyYXkgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIC8vIFRydW5jYXRpbmcgdGhlIGVsZW1lbnRzIGlzIHByb2JhYmx5IG5vdCB3aGF0IHBlb3BsZSBleHBlY3QgZnJvbSB0eXBlZFxuICAvLyBhcnJheXMgd2l0aCBCWVRFU19QRVJfRUxFTUVOVCA+IDEgYnV0IGl0J3MgY29tcGF0aWJsZSB3aXRoIHRoZSBiZWhhdmlvclxuICAvLyBvZiB0aGUgb2xkIEJ1ZmZlciBjb25zdHJ1Y3Rvci5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUJ1ZmZlciAodGhhdCwgYXJyYXkpIHtcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgYXJyYXkuYnl0ZUxlbmd0aFxuICAgIHRoYXQgPSBCdWZmZXIuX2F1Z21lbnQobmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0ID0gZnJvbVR5cGVkQXJyYXkodGhhdCwgbmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUxpa2UgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vLyBEZXNlcmlhbGl6ZSB7IHR5cGU6ICdCdWZmZXInLCBkYXRhOiBbMSwyLDMsLi4uXSB9IGludG8gYSBCdWZmZXIgb2JqZWN0LlxuLy8gUmV0dXJucyBhIHplcm8tbGVuZ3RoIGJ1ZmZlciBmb3IgaW5wdXRzIHRoYXQgZG9uJ3QgY29uZm9ybSB0byB0aGUgc3BlYy5cbmZ1bmN0aW9uIGZyb21Kc29uT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgdmFyIGFycmF5XG4gIHZhciBsZW5ndGggPSAwXG5cbiAgaWYgKG9iamVjdC50eXBlID09PSAnQnVmZmVyJyAmJiBpc0FycmF5KG9iamVjdC5kYXRhKSkge1xuICAgIGFycmF5ID0gb2JqZWN0LmRhdGFcbiAgICBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIH1cbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gIEJ1ZmZlci5wcm90b3R5cGUuX19wcm90b19fID0gVWludDhBcnJheS5wcm90b3R5cGVcbiAgQnVmZmVyLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXlcbn1cblxuZnVuY3Rpb24gYWxsb2NhdGUgKHRoYXQsIGxlbmd0aCkge1xuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAvLyBSZXR1cm4gYW4gYXVnbWVudGVkIGBVaW50OEFycmF5YCBpbnN0YW5jZSwgZm9yIGJlc3QgcGVyZm9ybWFuY2VcbiAgICB0aGF0ID0gQnVmZmVyLl9hdWdtZW50KG5ldyBVaW50OEFycmF5KGxlbmd0aCkpXG4gICAgdGhhdC5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgLy8gRmFsbGJhY2s6IFJldHVybiBhbiBvYmplY3QgaW5zdGFuY2Ugb2YgdGhlIEJ1ZmZlciBjbGFzc1xuICAgIHRoYXQubGVuZ3RoID0gbGVuZ3RoXG4gICAgdGhhdC5faXNCdWZmZXIgPSB0cnVlXG4gIH1cblxuICB2YXIgZnJvbVBvb2wgPSBsZW5ndGggIT09IDAgJiYgbGVuZ3RoIDw9IEJ1ZmZlci5wb29sU2l6ZSA+Pj4gMVxuICBpZiAoZnJvbVBvb2wpIHRoYXQucGFyZW50ID0gcm9vdFBhcmVudFxuXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGNoZWNrZWQgKGxlbmd0aCkge1xuICAvLyBOb3RlOiBjYW5ub3QgdXNlIGBsZW5ndGggPCBrTWF4TGVuZ3RoYCBoZXJlIGJlY2F1c2UgdGhhdCBmYWlscyB3aGVuXG4gIC8vIGxlbmd0aCBpcyBOYU4gKHdoaWNoIGlzIG90aGVyd2lzZSBjb2VyY2VkIHRvIHplcm8uKVxuICBpZiAobGVuZ3RoID49IGtNYXhMZW5ndGgoKSkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIGFsbG9jYXRlIEJ1ZmZlciBsYXJnZXIgdGhhbiBtYXhpbXVtICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICdzaXplOiAweCcgKyBrTWF4TGVuZ3RoKCkudG9TdHJpbmcoMTYpICsgJyBieXRlcycpXG4gIH1cbiAgcmV0dXJuIGxlbmd0aCB8IDBcbn1cblxuZnVuY3Rpb24gU2xvd0J1ZmZlciAoc3ViamVjdCwgZW5jb2RpbmcpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFNsb3dCdWZmZXIpKSByZXR1cm4gbmV3IFNsb3dCdWZmZXIoc3ViamVjdCwgZW5jb2RpbmcpXG5cbiAgdmFyIGJ1ZiA9IG5ldyBCdWZmZXIoc3ViamVjdCwgZW5jb2RpbmcpXG4gIGRlbGV0ZSBidWYucGFyZW50XG4gIHJldHVybiBidWZcbn1cblxuQnVmZmVyLmlzQnVmZmVyID0gZnVuY3Rpb24gaXNCdWZmZXIgKGIpIHtcbiAgcmV0dXJuICEhKGIgIT0gbnVsbCAmJiBiLl9pc0J1ZmZlcilcbn1cblxuQnVmZmVyLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChhLCBiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGEpIHx8ICFCdWZmZXIuaXNCdWZmZXIoYikpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudHMgbXVzdCBiZSBCdWZmZXJzJylcbiAgfVxuXG4gIGlmIChhID09PSBiKSByZXR1cm4gMFxuXG4gIHZhciB4ID0gYS5sZW5ndGhcbiAgdmFyIHkgPSBiLmxlbmd0aFxuXG4gIHZhciBpID0gMFxuICB2YXIgbGVuID0gTWF0aC5taW4oeCwgeSlcbiAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICBpZiAoYVtpXSAhPT0gYltpXSkgYnJlYWtcblxuICAgICsraVxuICB9XG5cbiAgaWYgKGkgIT09IGxlbikge1xuICAgIHggPSBhW2ldXG4gICAgeSA9IGJbaV1cbiAgfVxuXG4gIGlmICh4IDwgeSkgcmV0dXJuIC0xXG4gIGlmICh5IDwgeCkgcmV0dXJuIDFcbiAgcmV0dXJuIDBcbn1cblxuQnVmZmVyLmlzRW5jb2RpbmcgPSBmdW5jdGlvbiBpc0VuY29kaW5nIChlbmNvZGluZykge1xuICBzd2l0Y2ggKFN0cmluZyhlbmNvZGluZykudG9Mb3dlckNhc2UoKSkge1xuICAgIGNhc2UgJ2hleCc6XG4gICAgY2FzZSAndXRmOCc6XG4gICAgY2FzZSAndXRmLTgnOlxuICAgIGNhc2UgJ2FzY2lpJzpcbiAgICBjYXNlICdiaW5hcnknOlxuICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgY2FzZSAncmF3JzpcbiAgICBjYXNlICd1Y3MyJzpcbiAgICBjYXNlICd1Y3MtMic6XG4gICAgY2FzZSAndXRmMTZsZSc6XG4gICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgcmV0dXJuIHRydWVcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuQnVmZmVyLmNvbmNhdCA9IGZ1bmN0aW9uIGNvbmNhdCAobGlzdCwgbGVuZ3RoKSB7XG4gIGlmICghaXNBcnJheShsaXN0KSkgdGhyb3cgbmV3IFR5cGVFcnJvcignbGlzdCBhcmd1bWVudCBtdXN0IGJlIGFuIEFycmF5IG9mIEJ1ZmZlcnMuJylcblxuICBpZiAobGlzdC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcigwKVxuICB9XG5cbiAgdmFyIGlcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbGVuZ3RoID0gMFxuICAgIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBsZW5ndGggKz0gbGlzdFtpXS5sZW5ndGhcbiAgICB9XG4gIH1cblxuICB2YXIgYnVmID0gbmV3IEJ1ZmZlcihsZW5ndGgpXG4gIHZhciBwb3MgPSAwXG4gIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGl0ZW0gPSBsaXN0W2ldXG4gICAgaXRlbS5jb3B5KGJ1ZiwgcG9zKVxuICAgIHBvcyArPSBpdGVtLmxlbmd0aFxuICB9XG4gIHJldHVybiBidWZcbn1cblxuZnVuY3Rpb24gYnl0ZUxlbmd0aCAoc3RyaW5nLCBlbmNvZGluZykge1xuICBpZiAodHlwZW9mIHN0cmluZyAhPT0gJ3N0cmluZycpIHN0cmluZyA9ICcnICsgc3RyaW5nXG5cbiAgdmFyIGxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKGxlbiA9PT0gMCkgcmV0dXJuIDBcblxuICAvLyBVc2UgYSBmb3IgbG9vcCB0byBhdm9pZCByZWN1cnNpb25cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAvLyBEZXByZWNhdGVkXG4gICAgICBjYXNlICdyYXcnOlxuICAgICAgY2FzZSAncmF3cyc6XG4gICAgICAgIHJldHVybiBsZW5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGhcbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiBsZW4gKiAyXG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gbGVuID4+PiAxXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICByZXR1cm4gYmFzZTY0VG9CeXRlcyhzdHJpbmcpLmxlbmd0aFxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSByZXR1cm4gdXRmOFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGggLy8gYXNzdW1lIHV0ZjhcbiAgICAgICAgZW5jb2RpbmcgPSAoJycgKyBlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cbkJ1ZmZlci5ieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aFxuXG4vLyBwcmUtc2V0IGZvciB2YWx1ZXMgdGhhdCBtYXkgZXhpc3QgaW4gdGhlIGZ1dHVyZVxuQnVmZmVyLnByb3RvdHlwZS5sZW5ndGggPSB1bmRlZmluZWRcbkJ1ZmZlci5wcm90b3R5cGUucGFyZW50ID0gdW5kZWZpbmVkXG5cbmZ1bmN0aW9uIHNsb3dUb1N0cmluZyAoZW5jb2RpbmcsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcblxuICBzdGFydCA9IHN0YXJ0IHwgMFxuICBlbmQgPSBlbmQgPT09IHVuZGVmaW5lZCB8fCBlbmQgPT09IEluZmluaXR5ID8gdGhpcy5sZW5ndGggOiBlbmQgfCAwXG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcbiAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKGVuZCA8PSBzdGFydCkgcmV0dXJuICcnXG5cbiAgd2hpbGUgKHRydWUpIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1dGYxNmxlU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKGVuY29kaW5nICsgJycpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9TdHJpbmcgPSBmdW5jdGlvbiB0b1N0cmluZyAoKSB7XG4gIHZhciBsZW5ndGggPSB0aGlzLmxlbmd0aCB8IDBcbiAgaWYgKGxlbmd0aCA9PT0gMCkgcmV0dXJuICcnXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSByZXR1cm4gdXRmOFNsaWNlKHRoaXMsIDAsIGxlbmd0aClcbiAgcmV0dXJuIHNsb3dUb1N0cmluZy5hcHBseSh0aGlzLCBhcmd1bWVudHMpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24gZXF1YWxzIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiB0cnVlXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKSA9PT0gMFxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluc3BlY3QgPSBmdW5jdGlvbiBpbnNwZWN0ICgpIHtcbiAgdmFyIHN0ciA9ICcnXG4gIHZhciBtYXggPSBleHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTXG4gIGlmICh0aGlzLmxlbmd0aCA+IDApIHtcbiAgICBzdHIgPSB0aGlzLnRvU3RyaW5nKCdoZXgnLCAwLCBtYXgpLm1hdGNoKC8uezJ9L2cpLmpvaW4oJyAnKVxuICAgIGlmICh0aGlzLmxlbmd0aCA+IG1heCkgc3RyICs9ICcgLi4uICdcbiAgfVxuICByZXR1cm4gJzxCdWZmZXIgJyArIHN0ciArICc+J1xufVxuXG5CdWZmZXIucHJvdG90eXBlLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiAwXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluZGV4T2YgPSBmdW5jdGlvbiBpbmRleE9mICh2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgaWYgKGJ5dGVPZmZzZXQgPiAweDdmZmZmZmZmKSBieXRlT2Zmc2V0ID0gMHg3ZmZmZmZmZlxuICBlbHNlIGlmIChieXRlT2Zmc2V0IDwgLTB4ODAwMDAwMDApIGJ5dGVPZmZzZXQgPSAtMHg4MDAwMDAwMFxuICBieXRlT2Zmc2V0ID4+PSAwXG5cbiAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gLTFcbiAgaWYgKGJ5dGVPZmZzZXQgPj0gdGhpcy5sZW5ndGgpIHJldHVybiAtMVxuXG4gIC8vIE5lZ2F0aXZlIG9mZnNldHMgc3RhcnQgZnJvbSB0aGUgZW5kIG9mIHRoZSBidWZmZXJcbiAgaWYgKGJ5dGVPZmZzZXQgPCAwKSBieXRlT2Zmc2V0ID0gTWF0aC5tYXgodGhpcy5sZW5ndGggKyBieXRlT2Zmc2V0LCAwKVxuXG4gIGlmICh0eXBlb2YgdmFsID09PSAnc3RyaW5nJykge1xuICAgIGlmICh2YWwubGVuZ3RoID09PSAwKSByZXR1cm4gLTEgLy8gc3BlY2lhbCBjYXNlOiBsb29raW5nIGZvciBlbXB0eSBzdHJpbmcgYWx3YXlzIGZhaWxzXG4gICAgcmV0dXJuIFN0cmluZy5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAoQnVmZmVyLmlzQnVmZmVyKHZhbCkpIHtcbiAgICByZXR1cm4gYXJyYXlJbmRleE9mKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ251bWJlcicpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQgJiYgVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgcmV0dXJuIFVpbnQ4QXJyYXkucHJvdG90eXBlLmluZGV4T2YuY2FsbCh0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gICAgfVxuICAgIHJldHVybiBhcnJheUluZGV4T2YodGhpcywgWyB2YWwgXSwgYnl0ZU9mZnNldClcbiAgfVxuXG4gIGZ1bmN0aW9uIGFycmF5SW5kZXhPZiAoYXJyLCB2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgICB2YXIgZm91bmRJbmRleCA9IC0xXG4gICAgZm9yICh2YXIgaSA9IDA7IGJ5dGVPZmZzZXQgKyBpIDwgYXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoYXJyW2J5dGVPZmZzZXQgKyBpXSA9PT0gdmFsW2ZvdW5kSW5kZXggPT09IC0xID8gMCA6IGkgLSBmb3VuZEluZGV4XSkge1xuICAgICAgICBpZiAoZm91bmRJbmRleCA9PT0gLTEpIGZvdW5kSW5kZXggPSBpXG4gICAgICAgIGlmIChpIC0gZm91bmRJbmRleCArIDEgPT09IHZhbC5sZW5ndGgpIHJldHVybiBieXRlT2Zmc2V0ICsgZm91bmRJbmRleFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZm91bmRJbmRleCA9IC0xXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAtMVxuICB9XG5cbiAgdGhyb3cgbmV3IFR5cGVFcnJvcigndmFsIG11c3QgYmUgc3RyaW5nLCBudW1iZXIgb3IgQnVmZmVyJylcbn1cblxuLy8gYGdldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5nZXQgPSBmdW5jdGlvbiBnZXQgKG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLmdldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMucmVhZFVJbnQ4KG9mZnNldClcbn1cblxuLy8gYHNldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5zZXQgPSBmdW5jdGlvbiBzZXQgKHYsIG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLnNldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMud3JpdGVVSW50OCh2LCBvZmZzZXQpXG59XG5cbmZ1bmN0aW9uIGhleFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgb2Zmc2V0ID0gTnVtYmVyKG9mZnNldCkgfHwgMFxuICB2YXIgcmVtYWluaW5nID0gYnVmLmxlbmd0aCAtIG9mZnNldFxuICBpZiAoIWxlbmd0aCkge1xuICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICB9IGVsc2Uge1xuICAgIGxlbmd0aCA9IE51bWJlcihsZW5ndGgpXG4gICAgaWYgKGxlbmd0aCA+IHJlbWFpbmluZykge1xuICAgICAgbGVuZ3RoID0gcmVtYWluaW5nXG4gICAgfVxuICB9XG5cbiAgLy8gbXVzdCBiZSBhbiBldmVuIG51bWJlciBvZiBkaWdpdHNcbiAgdmFyIHN0ckxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKHN0ckxlbiAlIDIgIT09IDApIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcblxuICBpZiAobGVuZ3RoID4gc3RyTGVuIC8gMikge1xuICAgIGxlbmd0aCA9IHN0ckxlbiAvIDJcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHBhcnNlZCA9IHBhcnNlSW50KHN0cmluZy5zdWJzdHIoaSAqIDIsIDIpLCAxNilcbiAgICBpZiAoaXNOYU4ocGFyc2VkKSkgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGhleCBzdHJpbmcnKVxuICAgIGJ1ZltvZmZzZXQgKyBpXSA9IHBhcnNlZFxuICB9XG4gIHJldHVybiBpXG59XG5cbmZ1bmN0aW9uIHV0ZjhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKHV0ZjhUb0J5dGVzKHN0cmluZywgYnVmLmxlbmd0aCAtIG9mZnNldCksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGFzY2lpV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcihhc2NpaVRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYmluYXJ5V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYXNjaWlXcml0ZShidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGJhc2U2NFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIoYmFzZTY0VG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiB1Y3MyV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcih1dGYxNmxlVG9CeXRlcyhzdHJpbmcsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlID0gZnVuY3Rpb24gd3JpdGUgKHN0cmluZywgb2Zmc2V0LCBsZW5ndGgsIGVuY29kaW5nKSB7XG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcpXG4gIGlmIChvZmZzZXQgPT09IHVuZGVmaW5lZCkge1xuICAgIGVuY29kaW5nID0gJ3V0ZjgnXG4gICAgbGVuZ3RoID0gdGhpcy5sZW5ndGhcbiAgICBvZmZzZXQgPSAwXG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICB9IGVsc2UgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkICYmIHR5cGVvZiBvZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgZW5jb2RpbmcgPSBvZmZzZXRcbiAgICBsZW5ndGggPSB0aGlzLmxlbmd0aFxuICAgIG9mZnNldCA9IDBcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZywgb2Zmc2V0WywgbGVuZ3RoXVssIGVuY29kaW5nXSlcbiAgfSBlbHNlIGlmIChpc0Zpbml0ZShvZmZzZXQpKSB7XG4gICAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICAgIGlmIChpc0Zpbml0ZShsZW5ndGgpKSB7XG4gICAgICBsZW5ndGggPSBsZW5ndGggfCAwXG4gICAgICBpZiAoZW5jb2RpbmcgPT09IHVuZGVmaW5lZCkgZW5jb2RpbmcgPSAndXRmOCdcbiAgICB9IGVsc2Uge1xuICAgICAgZW5jb2RpbmcgPSBsZW5ndGhcbiAgICAgIGxlbmd0aCA9IHVuZGVmaW5lZFxuICAgIH1cbiAgLy8gbGVnYWN5IHdyaXRlKHN0cmluZywgZW5jb2RpbmcsIG9mZnNldCwgbGVuZ3RoKSAtIHJlbW92ZSBpbiB2MC4xM1xuICB9IGVsc2Uge1xuICAgIHZhciBzd2FwID0gZW5jb2RpbmdcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIG9mZnNldCA9IGxlbmd0aCB8IDBcbiAgICBsZW5ndGggPSBzd2FwXG4gIH1cblxuICB2YXIgcmVtYWluaW5nID0gdGhpcy5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkIHx8IGxlbmd0aCA+IHJlbWFpbmluZykgbGVuZ3RoID0gcmVtYWluaW5nXG5cbiAgaWYgKChzdHJpbmcubGVuZ3RoID4gMCAmJiAobGVuZ3RoIDwgMCB8fCBvZmZzZXQgPCAwKSkgfHwgb2Zmc2V0ID4gdGhpcy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignYXR0ZW1wdCB0byB3cml0ZSBvdXRzaWRlIGJ1ZmZlciBib3VuZHMnKVxuICB9XG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcblxuICB2YXIgbG93ZXJlZENhc2UgPSBmYWxzZVxuICBmb3IgKDs7KSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGhleFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgICAgcmV0dXJuIGFzY2lpV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgICAgcmV0dXJuIGJpbmFyeVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIC8vIFdhcm5pbmc6IG1heExlbmd0aCBub3QgdGFrZW4gaW50byBhY2NvdW50IGluIGJhc2U2NFdyaXRlXG4gICAgICAgIHJldHVybiBiYXNlNjRXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gdWNzMldyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgICAgICBlbmNvZGluZyA9ICgnJyArIGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvSlNPTiA9IGZ1bmN0aW9uIHRvSlNPTiAoKSB7XG4gIHJldHVybiB7XG4gICAgdHlwZTogJ0J1ZmZlcicsXG4gICAgZGF0YTogQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodGhpcy5fYXJyIHx8IHRoaXMsIDApXG4gIH1cbn1cblxuZnVuY3Rpb24gYmFzZTY0U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICBpZiAoc3RhcnQgPT09IDAgJiYgZW5kID09PSBidWYubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGJhc2U2NC5mcm9tQnl0ZUFycmF5KGJ1ZilcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmLnNsaWNlKHN0YXJ0LCBlbmQpKVxuICB9XG59XG5cbmZ1bmN0aW9uIHV0ZjhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcbiAgdmFyIHJlcyA9IFtdXG5cbiAgdmFyIGkgPSBzdGFydFxuICB3aGlsZSAoaSA8IGVuZCkge1xuICAgIHZhciBmaXJzdEJ5dGUgPSBidWZbaV1cbiAgICB2YXIgY29kZVBvaW50ID0gbnVsbFxuICAgIHZhciBieXRlc1BlclNlcXVlbmNlID0gKGZpcnN0Qnl0ZSA+IDB4RUYpID8gNFxuICAgICAgOiAoZmlyc3RCeXRlID4gMHhERikgPyAzXG4gICAgICA6IChmaXJzdEJ5dGUgPiAweEJGKSA/IDJcbiAgICAgIDogMVxuXG4gICAgaWYgKGkgKyBieXRlc1BlclNlcXVlbmNlIDw9IGVuZCkge1xuICAgICAgdmFyIHNlY29uZEJ5dGUsIHRoaXJkQnl0ZSwgZm91cnRoQnl0ZSwgdGVtcENvZGVQb2ludFxuXG4gICAgICBzd2l0Y2ggKGJ5dGVzUGVyU2VxdWVuY2UpIHtcbiAgICAgICAgY2FzZSAxOlxuICAgICAgICAgIGlmIChmaXJzdEJ5dGUgPCAweDgwKSB7XG4gICAgICAgICAgICBjb2RlUG9pbnQgPSBmaXJzdEJ5dGVcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHgxRikgPDwgMHg2IHwgKHNlY29uZEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweDdGKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwICYmICh0aGlyZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4QyB8IChzZWNvbmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKHRoaXJkQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0ZGICYmICh0ZW1wQ29kZVBvaW50IDwgMHhEODAwIHx8IHRlbXBDb2RlUG9pbnQgPiAweERGRkYpKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSA0OlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGZvdXJ0aEJ5dGUgPSBidWZbaSArIDNdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwICYmIChmb3VydGhCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHhGKSA8PCAweDEyIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweEMgfCAodGhpcmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKGZvdXJ0aEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweEZGRkYgJiYgdGVtcENvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGNvZGVQb2ludCA9PT0gbnVsbCkge1xuICAgICAgLy8gd2UgZGlkIG5vdCBnZW5lcmF0ZSBhIHZhbGlkIGNvZGVQb2ludCBzbyBpbnNlcnQgYVxuICAgICAgLy8gcmVwbGFjZW1lbnQgY2hhciAoVStGRkZEKSBhbmQgYWR2YW5jZSBvbmx5IDEgYnl0ZVxuICAgICAgY29kZVBvaW50ID0gMHhGRkZEXG4gICAgICBieXRlc1BlclNlcXVlbmNlID0gMVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50ID4gMHhGRkZGKSB7XG4gICAgICAvLyBlbmNvZGUgdG8gdXRmMTYgKHN1cnJvZ2F0ZSBwYWlyIGRhbmNlKVxuICAgICAgY29kZVBvaW50IC09IDB4MTAwMDBcbiAgICAgIHJlcy5wdXNoKGNvZGVQb2ludCA+Pj4gMTAgJiAweDNGRiB8IDB4RDgwMClcbiAgICAgIGNvZGVQb2ludCA9IDB4REMwMCB8IGNvZGVQb2ludCAmIDB4M0ZGXG4gICAgfVxuXG4gICAgcmVzLnB1c2goY29kZVBvaW50KVxuICAgIGkgKz0gYnl0ZXNQZXJTZXF1ZW5jZVxuICB9XG5cbiAgcmV0dXJuIGRlY29kZUNvZGVQb2ludHNBcnJheShyZXMpXG59XG5cbi8vIEJhc2VkIG9uIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzIyNzQ3MjcyLzY4MDc0MiwgdGhlIGJyb3dzZXIgd2l0aFxuLy8gdGhlIGxvd2VzdCBsaW1pdCBpcyBDaHJvbWUsIHdpdGggMHgxMDAwMCBhcmdzLlxuLy8gV2UgZ28gMSBtYWduaXR1ZGUgbGVzcywgZm9yIHNhZmV0eVxudmFyIE1BWF9BUkdVTUVOVFNfTEVOR1RIID0gMHgxMDAwXG5cbmZ1bmN0aW9uIGRlY29kZUNvZGVQb2ludHNBcnJheSAoY29kZVBvaW50cykge1xuICB2YXIgbGVuID0gY29kZVBvaW50cy5sZW5ndGhcbiAgaWYgKGxlbiA8PSBNQVhfQVJHVU1FTlRTX0xFTkdUSCkge1xuICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFN0cmluZywgY29kZVBvaW50cykgLy8gYXZvaWQgZXh0cmEgc2xpY2UoKVxuICB9XG5cbiAgLy8gRGVjb2RlIGluIGNodW5rcyB0byBhdm9pZCBcImNhbGwgc3RhY2sgc2l6ZSBleGNlZWRlZFwiLlxuICB2YXIgcmVzID0gJydcbiAgdmFyIGkgPSAwXG4gIHdoaWxlIChpIDwgbGVuKSB7XG4gICAgcmVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoXG4gICAgICBTdHJpbmcsXG4gICAgICBjb2RlUG9pbnRzLnNsaWNlKGksIGkgKz0gTUFYX0FSR1VNRU5UU19MRU5HVEgpXG4gICAgKVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0gJiAweDdGKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gYmluYXJ5U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgcmV0ID0gJydcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgcmV0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnVmW2ldKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gaGV4U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gYnVmLmxlbmd0aFxuXG4gIGlmICghc3RhcnQgfHwgc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgfHwgZW5kIDwgMCB8fCBlbmQgPiBsZW4pIGVuZCA9IGxlblxuXG4gIHZhciBvdXQgPSAnJ1xuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIG91dCArPSB0b0hleChidWZbaV0pXG4gIH1cbiAgcmV0dXJuIG91dFxufVxuXG5mdW5jdGlvbiB1dGYxNmxlU2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgYnl0ZXMgPSBidWYuc2xpY2Uoc3RhcnQsIGVuZClcbiAgdmFyIHJlcyA9ICcnXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShieXRlc1tpXSArIGJ5dGVzW2kgKyAxXSAqIDI1NilcbiAgfVxuICByZXR1cm4gcmVzXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuc2xpY2UgPSBmdW5jdGlvbiBzbGljZSAoc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gdGhpcy5sZW5ndGhcbiAgc3RhcnQgPSB+fnN0YXJ0XG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkID8gbGVuIDogfn5lbmRcblxuICBpZiAoc3RhcnQgPCAwKSB7XG4gICAgc3RhcnQgKz0gbGVuXG4gICAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIH0gZWxzZSBpZiAoc3RhcnQgPiBsZW4pIHtcbiAgICBzdGFydCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IDApIHtcbiAgICBlbmQgKz0gbGVuXG4gICAgaWYgKGVuZCA8IDApIGVuZCA9IDBcbiAgfSBlbHNlIGlmIChlbmQgPiBsZW4pIHtcbiAgICBlbmQgPSBsZW5cbiAgfVxuXG4gIGlmIChlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICB2YXIgbmV3QnVmXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIG5ld0J1ZiA9IEJ1ZmZlci5fYXVnbWVudCh0aGlzLnN1YmFycmF5KHN0YXJ0LCBlbmQpKVxuICB9IGVsc2Uge1xuICAgIHZhciBzbGljZUxlbiA9IGVuZCAtIHN0YXJ0XG4gICAgbmV3QnVmID0gbmV3IEJ1ZmZlcihzbGljZUxlbiwgdW5kZWZpbmVkKVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2xpY2VMZW47IGkrKykge1xuICAgICAgbmV3QnVmW2ldID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9XG5cbiAgaWYgKG5ld0J1Zi5sZW5ndGgpIG5ld0J1Zi5wYXJlbnQgPSB0aGlzLnBhcmVudCB8fCB0aGlzXG5cbiAgcmV0dXJuIG5ld0J1ZlxufVxuXG4vKlxuICogTmVlZCB0byBtYWtlIHN1cmUgdGhhdCBidWZmZXIgaXNuJ3QgdHJ5aW5nIHRvIHdyaXRlIG91dCBvZiBib3VuZHMuXG4gKi9cbmZ1bmN0aW9uIGNoZWNrT2Zmc2V0IChvZmZzZXQsIGV4dCwgbGVuZ3RoKSB7XG4gIGlmICgob2Zmc2V0ICUgMSkgIT09IDAgfHwgb2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ29mZnNldCBpcyBub3QgdWludCcpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBsZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdUcnlpbmcgdG8gYWNjZXNzIGJleW9uZCBidWZmZXIgbGVuZ3RoJylcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludExFID0gZnVuY3Rpb24gcmVhZFVJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludEJFID0gZnVuY3Rpb24gcmVhZFVJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcbiAgfVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIC0tYnl0ZUxlbmd0aF1cbiAgdmFyIG11bCA9IDFcbiAgd2hpbGUgKGJ5dGVMZW5ndGggPiAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50OCA9IGZ1bmN0aW9uIHJlYWRVSW50OCAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDEsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gdGhpc1tvZmZzZXRdXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkxFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MTZCRSA9IGZ1bmN0aW9uIHJlYWRVSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCA4KSB8IHRoaXNbb2Zmc2V0ICsgMV1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyTEUgPSBmdW5jdGlvbiByZWFkVUludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKCh0aGlzW29mZnNldF0pIHxcbiAgICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAgICh0aGlzW29mZnNldCArIDJdIDw8IDE2KSkgK1xuICAgICAgKHRoaXNbb2Zmc2V0ICsgM10gKiAweDEwMDAwMDApXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQzMkJFID0gZnVuY3Rpb24gcmVhZFVJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gKiAweDEwMDAwMDApICtcbiAgICAoKHRoaXNbb2Zmc2V0ICsgMV0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCA4KSB8XG4gICAgdGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50TEUgPSBmdW5jdGlvbiByZWFkSW50TEUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIGldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50QkUgPSBmdW5jdGlvbiByZWFkSW50QkUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgaSA9IGJ5dGVMZW5ndGhcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1pXVxuICB3aGlsZSAoaSA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50OCA9IGZ1bmN0aW9uIHJlYWRJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIGlmICghKHRoaXNbb2Zmc2V0XSAmIDB4ODApKSByZXR1cm4gKHRoaXNbb2Zmc2V0XSlcbiAgcmV0dXJuICgoMHhmZiAtIHRoaXNbb2Zmc2V0XSArIDEpICogLTEpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2TEUgPSBmdW5jdGlvbiByZWFkSW50MTZMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdIHwgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQxNkJFID0gZnVuY3Rpb24gcmVhZEludDE2QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgMV0gfCAodGhpc1tvZmZzZXRdIDw8IDgpXG4gIHJldHVybiAodmFsICYgMHg4MDAwKSA/IHZhbCB8IDB4RkZGRjAwMDAgOiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0pIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSA8PCAyNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJCRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gPDwgMjQpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRMRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdExFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRCRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdEJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCBmYWxzZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUxFID0gZnVuY3Rpb24gcmVhZERvdWJsZUxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgOCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCA1MiwgOClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlQkUgPSBmdW5jdGlvbiByZWFkRG91YmxlQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCA1MiwgOClcbn1cblxuZnVuY3Rpb24gY2hlY2tJbnQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihidWYpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdidWZmZXIgbXVzdCBiZSBhIEJ1ZmZlciBpbnN0YW5jZScpXG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3ZhbHVlIGlzIG91dCBvZiBib3VuZHMnKVxuICBpZiAob2Zmc2V0ICsgZXh0ID4gYnVmLmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB0aGlzW29mZnNldF0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50QkUgPSBmdW5jdGlvbiB3cml0ZVVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aCAtIDFcbiAgdmFyIG11bCA9IDFcbiAgdGhpc1tvZmZzZXQgKyBpXSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoLS1pID49IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50OCA9IGZ1bmN0aW9uIHdyaXRlVUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHhmZiwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkgdmFsdWUgPSBNYXRoLmZsb29yKHZhbHVlKVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQxNiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmYgKyB2YWx1ZSArIDFcbiAgZm9yICh2YXIgaSA9IDAsIGogPSBNYXRoLm1pbihidWYubGVuZ3RoIC0gb2Zmc2V0LCAyKTsgaSA8IGo7IGkrKykge1xuICAgIGJ1ZltvZmZzZXQgKyBpXSA9ICh2YWx1ZSAmICgweGZmIDw8ICg4ICogKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkpKSkgPj4+XG4gICAgICAobGl0dGxlRW5kaWFuID8gaSA6IDEgLSBpKSAqIDhcbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDE2TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4ZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQzMiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgNCk7IGkgPCBqOyBpKyspIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgPj4+IChsaXR0bGVFbmRpYW4gPyBpIDogMyAtIGkpICogOCkgJiAweGZmXG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDMyQkUgPSBmdW5jdGlvbiB3cml0ZVVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4ZmZmZmZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50TEUgPSBmdW5jdGlvbiB3cml0ZUludExFICh2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbGltaXQgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCAtIDEpXG5cbiAgICBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBsaW1pdCAtIDEsIC1saW1pdClcbiAgfVxuXG4gIHZhciBpID0gMFxuICB2YXIgbXVsID0gMVxuICB2YXIgc3ViID0gdmFsdWUgPCAwID8gMSA6IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludEJFID0gZnVuY3Rpb24gd3JpdGVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSB2YWx1ZSA8IDAgPyAxIDogMFxuICB0aGlzW29mZnNldCArIGldID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgtLWkgPj0gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAoKHZhbHVlIC8gbXVsKSA+PiAwKSAtIHN1YiAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQ4ID0gZnVuY3Rpb24gd3JpdGVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4N2YsIC0weDgwKVxuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB2YWx1ZSA9IE1hdGguZmxvb3IodmFsdWUpXG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZiArIHZhbHVlICsgMVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MTZMRSA9IGZ1bmN0aW9uIHdyaXRlSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweDdmZmYsIC0weDgwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MzJCRSA9IGZ1bmN0aW9uIHdyaXRlSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweDdmZmZmZmZmLCAtMHg4MDAwMDAwMClcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5mdW5jdGlvbiBjaGVja0lFRUU3NTQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAodmFsdWUgPiBtYXggfHwgdmFsdWUgPCBtaW4pIHRocm93IG5ldyBSYW5nZUVycm9yKCd2YWx1ZSBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxuICBpZiAob2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRmxvYXQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgNCwgMy40MDI4MjM0NjYzODUyODg2ZSszOCwgLTMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgMjMsIDQpXG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdExFID0gZnVuY3Rpb24gd3JpdGVGbG9hdExFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUZsb2F0QkUgPSBmdW5jdGlvbiB3cml0ZUZsb2F0QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZUZsb2F0KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuZnVuY3Rpb24gd3JpdGVEb3VibGUgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgOCwgMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgsIC0xLjc5NzY5MzEzNDg2MjMxNTdFKzMwOClcbiAgfVxuICBpZWVlNzU0LndyaXRlKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCA1MiwgOClcbiAgcmV0dXJuIG9mZnNldCArIDhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUxFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUsIG5vQXNzZXJ0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRG91YmxlQkUgPSBmdW5jdGlvbiB3cml0ZURvdWJsZUJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVEb3VibGUodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UsIG5vQXNzZXJ0KVxufVxuXG4vLyBjb3B5KHRhcmdldEJ1ZmZlciwgdGFyZ2V0U3RhcnQ9MCwgc291cmNlU3RhcnQ9MCwgc291cmNlRW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmNvcHkgPSBmdW5jdGlvbiBjb3B5ICh0YXJnZXQsIHRhcmdldFN0YXJ0LCBzdGFydCwgZW5kKSB7XG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCAmJiBlbmQgIT09IDApIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmICh0YXJnZXRTdGFydCA+PSB0YXJnZXQubGVuZ3RoKSB0YXJnZXRTdGFydCA9IHRhcmdldC5sZW5ndGhcbiAgaWYgKCF0YXJnZXRTdGFydCkgdGFyZ2V0U3RhcnQgPSAwXG4gIGlmIChlbmQgPiAwICYmIGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIC8vIENvcHkgMCBieXRlczsgd2UncmUgZG9uZVxuICBpZiAoZW5kID09PSBzdGFydCkgcmV0dXJuIDBcbiAgaWYgKHRhcmdldC5sZW5ndGggPT09IDAgfHwgdGhpcy5sZW5ndGggPT09IDApIHJldHVybiAwXG5cbiAgLy8gRmF0YWwgZXJyb3IgY29uZGl0aW9uc1xuICBpZiAodGFyZ2V0U3RhcnQgPCAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3RhcmdldFN0YXJ0IG91dCBvZiBib3VuZHMnKVxuICB9XG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VFbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgLy8gQXJlIHdlIG9vYj9cbiAgaWYgKGVuZCA+IHRoaXMubGVuZ3RoKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0IDwgZW5kIC0gc3RhcnQpIHtcbiAgICBlbmQgPSB0YXJnZXQubGVuZ3RoIC0gdGFyZ2V0U3RhcnQgKyBzdGFydFxuICB9XG5cbiAgdmFyIGxlbiA9IGVuZCAtIHN0YXJ0XG4gIHZhciBpXG5cbiAgaWYgKHRoaXMgPT09IHRhcmdldCAmJiBzdGFydCA8IHRhcmdldFN0YXJ0ICYmIHRhcmdldFN0YXJ0IDwgZW5kKSB7XG4gICAgLy8gZGVzY2VuZGluZyBjb3B5IGZyb20gZW5kXG4gICAgZm9yIChpID0gbGVuIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2UgaWYgKGxlbiA8IDEwMDAgfHwgIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gYXNjZW5kaW5nIGNvcHkgZnJvbSBzdGFydFxuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgdGFyZ2V0W2kgKyB0YXJnZXRTdGFydF0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGFyZ2V0Ll9zZXQodGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLCB0YXJnZXRTdGFydClcbiAgfVxuXG4gIHJldHVybiBsZW5cbn1cblxuLy8gZmlsbCh2YWx1ZSwgc3RhcnQ9MCwgZW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmZpbGwgPSBmdW5jdGlvbiBmaWxsICh2YWx1ZSwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXZhbHVlKSB2YWx1ZSA9IDBcbiAgaWYgKCFzdGFydCkgc3RhcnQgPSAwXG4gIGlmICghZW5kKSBlbmQgPSB0aGlzLmxlbmd0aFxuXG4gIGlmIChlbmQgPCBzdGFydCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2VuZCA8IHN0YXJ0JylcblxuICAvLyBGaWxsIDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVyblxuICBpZiAodGhpcy5sZW5ndGggPT09IDApIHJldHVyblxuXG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDAgfHwgZW5kID4gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdlbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgdmFyIGlcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICBmb3IgKGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgICB0aGlzW2ldID0gdmFsdWVcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFyIGJ5dGVzID0gdXRmOFRvQnl0ZXModmFsdWUudG9TdHJpbmcoKSlcbiAgICB2YXIgbGVuID0gYnl0ZXMubGVuZ3RoXG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdGhpc1tpXSA9IGJ5dGVzW2kgJSBsZW5dXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXNcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IGBBcnJheUJ1ZmZlcmAgd2l0aCB0aGUgKmNvcGllZCogbWVtb3J5IG9mIHRoZSBidWZmZXIgaW5zdGFuY2UuXG4gKiBBZGRlZCBpbiBOb2RlIDAuMTIuIE9ubHkgYXZhaWxhYmxlIGluIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCBBcnJheUJ1ZmZlci5cbiAqL1xuQnVmZmVyLnByb3RvdHlwZS50b0FycmF5QnVmZmVyID0gZnVuY3Rpb24gdG9BcnJheUJ1ZmZlciAoKSB7XG4gIGlmICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAgIHJldHVybiAobmV3IEJ1ZmZlcih0aGlzKSkuYnVmZmVyXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBidWYgPSBuZXcgVWludDhBcnJheSh0aGlzLmxlbmd0aClcbiAgICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBidWYubGVuZ3RoOyBpIDwgbGVuOyBpICs9IDEpIHtcbiAgICAgICAgYnVmW2ldID0gdGhpc1tpXVxuICAgICAgfVxuICAgICAgcmV0dXJuIGJ1Zi5idWZmZXJcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQnVmZmVyLnRvQXJyYXlCdWZmZXIgbm90IHN1cHBvcnRlZCBpbiB0aGlzIGJyb3dzZXInKVxuICB9XG59XG5cbi8vIEhFTFBFUiBGVU5DVElPTlNcbi8vID09PT09PT09PT09PT09PT1cblxudmFyIEJQID0gQnVmZmVyLnByb3RvdHlwZVxuXG4vKipcbiAqIEF1Z21lbnQgYSBVaW50OEFycmF5ICppbnN0YW5jZSogKG5vdCB0aGUgVWludDhBcnJheSBjbGFzcyEpIHdpdGggQnVmZmVyIG1ldGhvZHNcbiAqL1xuQnVmZmVyLl9hdWdtZW50ID0gZnVuY3Rpb24gX2F1Z21lbnQgKGFycikge1xuICBhcnIuY29uc3RydWN0b3IgPSBCdWZmZXJcbiAgYXJyLl9pc0J1ZmZlciA9IHRydWVcblxuICAvLyBzYXZlIHJlZmVyZW5jZSB0byBvcmlnaW5hbCBVaW50OEFycmF5IHNldCBtZXRob2QgYmVmb3JlIG92ZXJ3cml0aW5nXG4gIGFyci5fc2V0ID0gYXJyLnNldFxuXG4gIC8vIGRlcHJlY2F0ZWRcbiAgYXJyLmdldCA9IEJQLmdldFxuICBhcnIuc2V0ID0gQlAuc2V0XG5cbiAgYXJyLndyaXRlID0gQlAud3JpdGVcbiAgYXJyLnRvU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvTG9jYWxlU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvSlNPTiA9IEJQLnRvSlNPTlxuICBhcnIuZXF1YWxzID0gQlAuZXF1YWxzXG4gIGFyci5jb21wYXJlID0gQlAuY29tcGFyZVxuICBhcnIuaW5kZXhPZiA9IEJQLmluZGV4T2ZcbiAgYXJyLmNvcHkgPSBCUC5jb3B5XG4gIGFyci5zbGljZSA9IEJQLnNsaWNlXG4gIGFyci5yZWFkVUludExFID0gQlAucmVhZFVJbnRMRVxuICBhcnIucmVhZFVJbnRCRSA9IEJQLnJlYWRVSW50QkVcbiAgYXJyLnJlYWRVSW50OCA9IEJQLnJlYWRVSW50OFxuICBhcnIucmVhZFVJbnQxNkxFID0gQlAucmVhZFVJbnQxNkxFXG4gIGFyci5yZWFkVUludDE2QkUgPSBCUC5yZWFkVUludDE2QkVcbiAgYXJyLnJlYWRVSW50MzJMRSA9IEJQLnJlYWRVSW50MzJMRVxuICBhcnIucmVhZFVJbnQzMkJFID0gQlAucmVhZFVJbnQzMkJFXG4gIGFyci5yZWFkSW50TEUgPSBCUC5yZWFkSW50TEVcbiAgYXJyLnJlYWRJbnRCRSA9IEJQLnJlYWRJbnRCRVxuICBhcnIucmVhZEludDggPSBCUC5yZWFkSW50OFxuICBhcnIucmVhZEludDE2TEUgPSBCUC5yZWFkSW50MTZMRVxuICBhcnIucmVhZEludDE2QkUgPSBCUC5yZWFkSW50MTZCRVxuICBhcnIucmVhZEludDMyTEUgPSBCUC5yZWFkSW50MzJMRVxuICBhcnIucmVhZEludDMyQkUgPSBCUC5yZWFkSW50MzJCRVxuICBhcnIucmVhZEZsb2F0TEUgPSBCUC5yZWFkRmxvYXRMRVxuICBhcnIucmVhZEZsb2F0QkUgPSBCUC5yZWFkRmxvYXRCRVxuICBhcnIucmVhZERvdWJsZUxFID0gQlAucmVhZERvdWJsZUxFXG4gIGFyci5yZWFkRG91YmxlQkUgPSBCUC5yZWFkRG91YmxlQkVcbiAgYXJyLndyaXRlVUludDggPSBCUC53cml0ZVVJbnQ4XG4gIGFyci53cml0ZVVJbnRMRSA9IEJQLndyaXRlVUludExFXG4gIGFyci53cml0ZVVJbnRCRSA9IEJQLndyaXRlVUludEJFXG4gIGFyci53cml0ZVVJbnQxNkxFID0gQlAud3JpdGVVSW50MTZMRVxuICBhcnIud3JpdGVVSW50MTZCRSA9IEJQLndyaXRlVUludDE2QkVcbiAgYXJyLndyaXRlVUludDMyTEUgPSBCUC53cml0ZVVJbnQzMkxFXG4gIGFyci53cml0ZVVJbnQzMkJFID0gQlAud3JpdGVVSW50MzJCRVxuICBhcnIud3JpdGVJbnRMRSA9IEJQLndyaXRlSW50TEVcbiAgYXJyLndyaXRlSW50QkUgPSBCUC53cml0ZUludEJFXG4gIGFyci53cml0ZUludDggPSBCUC53cml0ZUludDhcbiAgYXJyLndyaXRlSW50MTZMRSA9IEJQLndyaXRlSW50MTZMRVxuICBhcnIud3JpdGVJbnQxNkJFID0gQlAud3JpdGVJbnQxNkJFXG4gIGFyci53cml0ZUludDMyTEUgPSBCUC53cml0ZUludDMyTEVcbiAgYXJyLndyaXRlSW50MzJCRSA9IEJQLndyaXRlSW50MzJCRVxuICBhcnIud3JpdGVGbG9hdExFID0gQlAud3JpdGVGbG9hdExFXG4gIGFyci53cml0ZUZsb2F0QkUgPSBCUC53cml0ZUZsb2F0QkVcbiAgYXJyLndyaXRlRG91YmxlTEUgPSBCUC53cml0ZURvdWJsZUxFXG4gIGFyci53cml0ZURvdWJsZUJFID0gQlAud3JpdGVEb3VibGVCRVxuICBhcnIuZmlsbCA9IEJQLmZpbGxcbiAgYXJyLmluc3BlY3QgPSBCUC5pbnNwZWN0XG4gIGFyci50b0FycmF5QnVmZmVyID0gQlAudG9BcnJheUJ1ZmZlclxuXG4gIHJldHVybiBhcnJcbn1cblxudmFyIElOVkFMSURfQkFTRTY0X1JFID0gL1teK1xcLzAtOUEtWmEtei1fXS9nXG5cbmZ1bmN0aW9uIGJhc2U2NGNsZWFuIChzdHIpIHtcbiAgLy8gTm9kZSBzdHJpcHMgb3V0IGludmFsaWQgY2hhcmFjdGVycyBsaWtlIFxcbiBhbmQgXFx0IGZyb20gdGhlIHN0cmluZywgYmFzZTY0LWpzIGRvZXMgbm90XG4gIHN0ciA9IHN0cmluZ3RyaW0oc3RyKS5yZXBsYWNlKElOVkFMSURfQkFTRTY0X1JFLCAnJylcbiAgLy8gTm9kZSBjb252ZXJ0cyBzdHJpbmdzIHdpdGggbGVuZ3RoIDwgMiB0byAnJ1xuICBpZiAoc3RyLmxlbmd0aCA8IDIpIHJldHVybiAnJ1xuICAvLyBOb2RlIGFsbG93cyBmb3Igbm9uLXBhZGRlZCBiYXNlNjQgc3RyaW5ncyAobWlzc2luZyB0cmFpbGluZyA9PT0pLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgd2hpbGUgKHN0ci5sZW5ndGggJSA0ICE9PSAwKSB7XG4gICAgc3RyID0gc3RyICsgJz0nXG4gIH1cbiAgcmV0dXJuIHN0clxufVxuXG5mdW5jdGlvbiBzdHJpbmd0cmltIChzdHIpIHtcbiAgaWYgKHN0ci50cmltKSByZXR1cm4gc3RyLnRyaW0oKVxuICByZXR1cm4gc3RyLnJlcGxhY2UoL15cXHMrfFxccyskL2csICcnKVxufVxuXG5mdW5jdGlvbiB0b0hleCAobikge1xuICBpZiAobiA8IDE2KSByZXR1cm4gJzAnICsgbi50b1N0cmluZygxNilcbiAgcmV0dXJuIG4udG9TdHJpbmcoMTYpXG59XG5cbmZ1bmN0aW9uIHV0ZjhUb0J5dGVzIChzdHJpbmcsIHVuaXRzKSB7XG4gIHVuaXRzID0gdW5pdHMgfHwgSW5maW5pdHlcbiAgdmFyIGNvZGVQb2ludFxuICB2YXIgbGVuZ3RoID0gc3RyaW5nLmxlbmd0aFxuICB2YXIgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcbiAgdmFyIGJ5dGVzID0gW11cblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgY29kZVBvaW50ID0gc3RyaW5nLmNoYXJDb2RlQXQoaSlcblxuICAgIC8vIGlzIHN1cnJvZ2F0ZSBjb21wb25lbnRcbiAgICBpZiAoY29kZVBvaW50ID4gMHhEN0ZGICYmIGNvZGVQb2ludCA8IDB4RTAwMCkge1xuICAgICAgLy8gbGFzdCBjaGFyIHdhcyBhIGxlYWRcbiAgICAgIGlmICghbGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgICAvLyBubyBsZWFkIHlldFxuICAgICAgICBpZiAoY29kZVBvaW50ID4gMHhEQkZGKSB7XG4gICAgICAgICAgLy8gdW5leHBlY3RlZCB0cmFpbFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH0gZWxzZSBpZiAoaSArIDEgPT09IGxlbmd0aCkge1xuICAgICAgICAgIC8vIHVucGFpcmVkIGxlYWRcbiAgICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gdmFsaWQgbGVhZFxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG5cbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gMiBsZWFkcyBpbiBhIHJvd1xuICAgICAgaWYgKGNvZGVQb2ludCA8IDB4REMwMCkge1xuICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgbGVhZFN1cnJvZ2F0ZSA9IGNvZGVQb2ludFxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyB2YWxpZCBzdXJyb2dhdGUgcGFpclxuICAgICAgY29kZVBvaW50ID0gKGxlYWRTdXJyb2dhdGUgLSAweEQ4MDAgPDwgMTAgfCBjb2RlUG9pbnQgLSAweERDMDApICsgMHgxMDAwMFxuICAgIH0gZWxzZSBpZiAobGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgLy8gdmFsaWQgYm1wIGNoYXIsIGJ1dCBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgfVxuXG4gICAgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcblxuICAgIC8vIGVuY29kZSB1dGY4XG4gICAgaWYgKGNvZGVQb2ludCA8IDB4ODApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMSkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChjb2RlUG9pbnQpXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDgwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAyKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2IHwgMHhDMCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMykgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyB8IDB4RTAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDQpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDEyIHwgMHhGMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2ICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjb2RlIHBvaW50JylcbiAgICB9XG4gIH1cblxuICByZXR1cm4gYnl0ZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlUb0J5dGVzIChzdHIpIHtcbiAgdmFyIGJ5dGVBcnJheSA9IFtdXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgLy8gTm9kZSdzIGNvZGUgc2VlbXMgdG8gYmUgZG9pbmcgdGhpcyBhbmQgbm90ICYgMHg3Ri4uXG4gICAgYnl0ZUFycmF5LnB1c2goc3RyLmNoYXJDb2RlQXQoaSkgJiAweEZGKVxuICB9XG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gdXRmMTZsZVRvQnl0ZXMgKHN0ciwgdW5pdHMpIHtcbiAgdmFyIGMsIGhpLCBsb1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcblxuICAgIGMgPSBzdHIuY2hhckNvZGVBdChpKVxuICAgIGhpID0gYyA+PiA4XG4gICAgbG8gPSBjICUgMjU2XG4gICAgYnl0ZUFycmF5LnB1c2gobG8pXG4gICAgYnl0ZUFycmF5LnB1c2goaGkpXG4gIH1cblxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIGJhc2U2NFRvQnl0ZXMgKHN0cikge1xuICByZXR1cm4gYmFzZTY0LnRvQnl0ZUFycmF5KGJhc2U2NGNsZWFuKHN0cikpXG59XG5cbmZ1bmN0aW9uIGJsaXRCdWZmZXIgKHNyYywgZHN0LCBvZmZzZXQsIGxlbmd0aCkge1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKChpICsgb2Zmc2V0ID49IGRzdC5sZW5ndGgpIHx8IChpID49IHNyYy5sZW5ndGgpKSBicmVha1xuICAgIGRzdFtpICsgb2Zmc2V0XSA9IHNyY1tpXVxuICB9XG4gIHJldHVybiBpXG59XG4iLCJ2YXIgbG9va3VwID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky8nO1xuXG47KGZ1bmN0aW9uIChleHBvcnRzKSB7XG5cdCd1c2Ugc3RyaWN0JztcblxuICB2YXIgQXJyID0gKHR5cGVvZiBVaW50OEFycmF5ICE9PSAndW5kZWZpbmVkJylcbiAgICA/IFVpbnQ4QXJyYXlcbiAgICA6IEFycmF5XG5cblx0dmFyIFBMVVMgICA9ICcrJy5jaGFyQ29kZUF0KDApXG5cdHZhciBTTEFTSCAgPSAnLycuY2hhckNvZGVBdCgwKVxuXHR2YXIgTlVNQkVSID0gJzAnLmNoYXJDb2RlQXQoMClcblx0dmFyIExPV0VSICA9ICdhJy5jaGFyQ29kZUF0KDApXG5cdHZhciBVUFBFUiAgPSAnQScuY2hhckNvZGVBdCgwKVxuXHR2YXIgUExVU19VUkxfU0FGRSA9ICctJy5jaGFyQ29kZUF0KDApXG5cdHZhciBTTEFTSF9VUkxfU0FGRSA9ICdfJy5jaGFyQ29kZUF0KDApXG5cblx0ZnVuY3Rpb24gZGVjb2RlIChlbHQpIHtcblx0XHR2YXIgY29kZSA9IGVsdC5jaGFyQ29kZUF0KDApXG5cdFx0aWYgKGNvZGUgPT09IFBMVVMgfHxcblx0XHQgICAgY29kZSA9PT0gUExVU19VUkxfU0FGRSlcblx0XHRcdHJldHVybiA2MiAvLyAnKydcblx0XHRpZiAoY29kZSA9PT0gU0xBU0ggfHxcblx0XHQgICAgY29kZSA9PT0gU0xBU0hfVVJMX1NBRkUpXG5cdFx0XHRyZXR1cm4gNjMgLy8gJy8nXG5cdFx0aWYgKGNvZGUgPCBOVU1CRVIpXG5cdFx0XHRyZXR1cm4gLTEgLy9ubyBtYXRjaFxuXHRcdGlmIChjb2RlIDwgTlVNQkVSICsgMTApXG5cdFx0XHRyZXR1cm4gY29kZSAtIE5VTUJFUiArIDI2ICsgMjZcblx0XHRpZiAoY29kZSA8IFVQUEVSICsgMjYpXG5cdFx0XHRyZXR1cm4gY29kZSAtIFVQUEVSXG5cdFx0aWYgKGNvZGUgPCBMT1dFUiArIDI2KVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBMT1dFUiArIDI2XG5cdH1cblxuXHRmdW5jdGlvbiBiNjRUb0J5dGVBcnJheSAoYjY0KSB7XG5cdFx0dmFyIGksIGosIGwsIHRtcCwgcGxhY2VIb2xkZXJzLCBhcnJcblxuXHRcdGlmIChiNjQubGVuZ3RoICUgNCA+IDApIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzdHJpbmcuIExlbmd0aCBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgNCcpXG5cdFx0fVxuXG5cdFx0Ly8gdGhlIG51bWJlciBvZiBlcXVhbCBzaWducyAocGxhY2UgaG9sZGVycylcblx0XHQvLyBpZiB0aGVyZSBhcmUgdHdvIHBsYWNlaG9sZGVycywgdGhhbiB0aGUgdHdvIGNoYXJhY3RlcnMgYmVmb3JlIGl0XG5cdFx0Ly8gcmVwcmVzZW50IG9uZSBieXRlXG5cdFx0Ly8gaWYgdGhlcmUgaXMgb25seSBvbmUsIHRoZW4gdGhlIHRocmVlIGNoYXJhY3RlcnMgYmVmb3JlIGl0IHJlcHJlc2VudCAyIGJ5dGVzXG5cdFx0Ly8gdGhpcyBpcyBqdXN0IGEgY2hlYXAgaGFjayB0byBub3QgZG8gaW5kZXhPZiB0d2ljZVxuXHRcdHZhciBsZW4gPSBiNjQubGVuZ3RoXG5cdFx0cGxhY2VIb2xkZXJzID0gJz0nID09PSBiNjQuY2hhckF0KGxlbiAtIDIpID8gMiA6ICc9JyA9PT0gYjY0LmNoYXJBdChsZW4gLSAxKSA/IDEgOiAwXG5cblx0XHQvLyBiYXNlNjQgaXMgNC8zICsgdXAgdG8gdHdvIGNoYXJhY3RlcnMgb2YgdGhlIG9yaWdpbmFsIGRhdGFcblx0XHRhcnIgPSBuZXcgQXJyKGI2NC5sZW5ndGggKiAzIC8gNCAtIHBsYWNlSG9sZGVycylcblxuXHRcdC8vIGlmIHRoZXJlIGFyZSBwbGFjZWhvbGRlcnMsIG9ubHkgZ2V0IHVwIHRvIHRoZSBsYXN0IGNvbXBsZXRlIDQgY2hhcnNcblx0XHRsID0gcGxhY2VIb2xkZXJzID4gMCA/IGI2NC5sZW5ndGggLSA0IDogYjY0Lmxlbmd0aFxuXG5cdFx0dmFyIEwgPSAwXG5cblx0XHRmdW5jdGlvbiBwdXNoICh2KSB7XG5cdFx0XHRhcnJbTCsrXSA9IHZcblx0XHR9XG5cblx0XHRmb3IgKGkgPSAwLCBqID0gMDsgaSA8IGw7IGkgKz0gNCwgaiArPSAzKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDE4KSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDEyKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMikpIDw8IDYpIHwgZGVjb2RlKGI2NC5jaGFyQXQoaSArIDMpKVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwMDApID4+IDE2KVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwKSA+PiA4KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH1cblxuXHRcdGlmIChwbGFjZUhvbGRlcnMgPT09IDIpIHtcblx0XHRcdHRtcCA9IChkZWNvZGUoYjY0LmNoYXJBdChpKSkgPDwgMikgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA+PiA0KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH0gZWxzZSBpZiAocGxhY2VIb2xkZXJzID09PSAxKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDEwKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDQpIHwgKGRlY29kZShiNjQuY2hhckF0KGkgKyAyKSkgPj4gMilcblx0XHRcdHB1c2goKHRtcCA+PiA4KSAmIDB4RkYpXG5cdFx0XHRwdXNoKHRtcCAmIDB4RkYpXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGFyclxuXHR9XG5cblx0ZnVuY3Rpb24gdWludDhUb0Jhc2U2NCAodWludDgpIHtcblx0XHR2YXIgaSxcblx0XHRcdGV4dHJhQnl0ZXMgPSB1aW50OC5sZW5ndGggJSAzLCAvLyBpZiB3ZSBoYXZlIDEgYnl0ZSBsZWZ0LCBwYWQgMiBieXRlc1xuXHRcdFx0b3V0cHV0ID0gXCJcIixcblx0XHRcdHRlbXAsIGxlbmd0aFxuXG5cdFx0ZnVuY3Rpb24gZW5jb2RlIChudW0pIHtcblx0XHRcdHJldHVybiBsb29rdXAuY2hhckF0KG51bSlcblx0XHR9XG5cblx0XHRmdW5jdGlvbiB0cmlwbGV0VG9CYXNlNjQgKG51bSkge1xuXHRcdFx0cmV0dXJuIGVuY29kZShudW0gPj4gMTggJiAweDNGKSArIGVuY29kZShudW0gPj4gMTIgJiAweDNGKSArIGVuY29kZShudW0gPj4gNiAmIDB4M0YpICsgZW5jb2RlKG51bSAmIDB4M0YpXG5cdFx0fVxuXG5cdFx0Ly8gZ28gdGhyb3VnaCB0aGUgYXJyYXkgZXZlcnkgdGhyZWUgYnl0ZXMsIHdlJ2xsIGRlYWwgd2l0aCB0cmFpbGluZyBzdHVmZiBsYXRlclxuXHRcdGZvciAoaSA9IDAsIGxlbmd0aCA9IHVpbnQ4Lmxlbmd0aCAtIGV4dHJhQnl0ZXM7IGkgPCBsZW5ndGg7IGkgKz0gMykge1xuXHRcdFx0dGVtcCA9ICh1aW50OFtpXSA8PCAxNikgKyAodWludDhbaSArIDFdIDw8IDgpICsgKHVpbnQ4W2kgKyAyXSlcblx0XHRcdG91dHB1dCArPSB0cmlwbGV0VG9CYXNlNjQodGVtcClcblx0XHR9XG5cblx0XHQvLyBwYWQgdGhlIGVuZCB3aXRoIHplcm9zLCBidXQgbWFrZSBzdXJlIHRvIG5vdCBmb3JnZXQgdGhlIGV4dHJhIGJ5dGVzXG5cdFx0c3dpdGNoIChleHRyYUJ5dGVzKSB7XG5cdFx0XHRjYXNlIDE6XG5cdFx0XHRcdHRlbXAgPSB1aW50OFt1aW50OC5sZW5ndGggLSAxXVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKHRlbXAgPj4gMilcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA8PCA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSAnPT0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0XHRjYXNlIDI6XG5cdFx0XHRcdHRlbXAgPSAodWludDhbdWludDgubGVuZ3RoIC0gMl0gPDwgOCkgKyAodWludDhbdWludDgubGVuZ3RoIC0gMV0pXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUodGVtcCA+PiAxMClcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA+PiA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPDwgMikgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gJz0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG91dHB1dFxuXHR9XG5cblx0ZXhwb3J0cy50b0J5dGVBcnJheSA9IGI2NFRvQnl0ZUFycmF5XG5cdGV4cG9ydHMuZnJvbUJ5dGVBcnJheSA9IHVpbnQ4VG9CYXNlNjRcbn0odHlwZW9mIGV4cG9ydHMgPT09ICd1bmRlZmluZWQnID8gKHRoaXMuYmFzZTY0anMgPSB7fSkgOiBleHBvcnRzKSlcbiIsImV4cG9ydHMucmVhZCA9IGZ1bmN0aW9uIChidWZmZXIsIG9mZnNldCwgaXNMRSwgbUxlbiwgbkJ5dGVzKSB7XG4gIHZhciBlLCBtXG4gIHZhciBlTGVuID0gbkJ5dGVzICogOCAtIG1MZW4gLSAxXG4gIHZhciBlTWF4ID0gKDEgPDwgZUxlbikgLSAxXG4gIHZhciBlQmlhcyA9IGVNYXggPj4gMVxuICB2YXIgbkJpdHMgPSAtN1xuICB2YXIgaSA9IGlzTEUgPyAobkJ5dGVzIC0gMSkgOiAwXG4gIHZhciBkID0gaXNMRSA/IC0xIDogMVxuICB2YXIgcyA9IGJ1ZmZlcltvZmZzZXQgKyBpXVxuXG4gIGkgKz0gZFxuXG4gIGUgPSBzICYgKCgxIDw8ICgtbkJpdHMpKSAtIDEpXG4gIHMgPj49ICgtbkJpdHMpXG4gIG5CaXRzICs9IGVMZW5cbiAgZm9yICg7IG5CaXRzID4gMDsgZSA9IGUgKiAyNTYgKyBidWZmZXJbb2Zmc2V0ICsgaV0sIGkgKz0gZCwgbkJpdHMgLT0gOCkge31cblxuICBtID0gZSAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBlID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBtTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IG0gPSBtICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgaWYgKGUgPT09IDApIHtcbiAgICBlID0gMSAtIGVCaWFzXG4gIH0gZWxzZSBpZiAoZSA9PT0gZU1heCkge1xuICAgIHJldHVybiBtID8gTmFOIDogKChzID8gLTEgOiAxKSAqIEluZmluaXR5KVxuICB9IGVsc2Uge1xuICAgIG0gPSBtICsgTWF0aC5wb3coMiwgbUxlbilcbiAgICBlID0gZSAtIGVCaWFzXG4gIH1cbiAgcmV0dXJuIChzID8gLTEgOiAxKSAqIG0gKiBNYXRoLnBvdygyLCBlIC0gbUxlbilcbn1cblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uIChidWZmZXIsIHZhbHVlLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbSwgY1xuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIHJ0ID0gKG1MZW4gPT09IDIzID8gTWF0aC5wb3coMiwgLTI0KSAtIE1hdGgucG93KDIsIC03NykgOiAwKVxuICB2YXIgaSA9IGlzTEUgPyAwIDogKG5CeXRlcyAtIDEpXG4gIHZhciBkID0gaXNMRSA/IDEgOiAtMVxuICB2YXIgcyA9IHZhbHVlIDwgMCB8fCAodmFsdWUgPT09IDAgJiYgMSAvIHZhbHVlIDwgMCkgPyAxIDogMFxuXG4gIHZhbHVlID0gTWF0aC5hYnModmFsdWUpXG5cbiAgaWYgKGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICBtID0gaXNOYU4odmFsdWUpID8gMSA6IDBcbiAgICBlID0gZU1heFxuICB9IGVsc2Uge1xuICAgIGUgPSBNYXRoLmZsb29yKE1hdGgubG9nKHZhbHVlKSAvIE1hdGguTE4yKVxuICAgIGlmICh2YWx1ZSAqIChjID0gTWF0aC5wb3coMiwgLWUpKSA8IDEpIHtcbiAgICAgIGUtLVxuICAgICAgYyAqPSAyXG4gICAgfVxuICAgIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgdmFsdWUgKz0gcnQgLyBjXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbHVlICs9IHJ0ICogTWF0aC5wb3coMiwgMSAtIGVCaWFzKVxuICAgIH1cbiAgICBpZiAodmFsdWUgKiBjID49IDIpIHtcbiAgICAgIGUrK1xuICAgICAgYyAvPSAyXG4gICAgfVxuXG4gICAgaWYgKGUgKyBlQmlhcyA+PSBlTWF4KSB7XG4gICAgICBtID0gMFxuICAgICAgZSA9IGVNYXhcbiAgICB9IGVsc2UgaWYgKGUgKyBlQmlhcyA+PSAxKSB7XG4gICAgICBtID0gKHZhbHVlICogYyAtIDEpICogTWF0aC5wb3coMiwgbUxlbilcbiAgICAgIGUgPSBlICsgZUJpYXNcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IHZhbHVlICogTWF0aC5wb3coMiwgZUJpYXMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gMFxuICAgIH1cbiAgfVxuXG4gIGZvciAoOyBtTGVuID49IDg7IGJ1ZmZlcltvZmZzZXQgKyBpXSA9IG0gJiAweGZmLCBpICs9IGQsIG0gLz0gMjU2LCBtTGVuIC09IDgpIHt9XG5cbiAgZSA9IChlIDw8IG1MZW4pIHwgbVxuICBlTGVuICs9IG1MZW5cbiAgZm9yICg7IGVMZW4gPiAwOyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBlICYgMHhmZiwgaSArPSBkLCBlIC89IDI1NiwgZUxlbiAtPSA4KSB7fVxuXG4gIGJ1ZmZlcltvZmZzZXQgKyBpIC0gZF0gfD0gcyAqIDEyOFxufVxuIiwiXG4vKipcbiAqIGlzQXJyYXlcbiAqL1xuXG52YXIgaXNBcnJheSA9IEFycmF5LmlzQXJyYXk7XG5cbi8qKlxuICogdG9TdHJpbmdcbiAqL1xuXG52YXIgc3RyID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztcblxuLyoqXG4gKiBXaGV0aGVyIG9yIG5vdCB0aGUgZ2l2ZW4gYHZhbGBcbiAqIGlzIGFuIGFycmF5LlxuICpcbiAqIGV4YW1wbGU6XG4gKlxuICogICAgICAgIGlzQXJyYXkoW10pO1xuICogICAgICAgIC8vID4gdHJ1ZVxuICogICAgICAgIGlzQXJyYXkoYXJndW1lbnRzKTtcbiAqICAgICAgICAvLyA+IGZhbHNlXG4gKiAgICAgICAgaXNBcnJheSgnJyk7XG4gKiAgICAgICAgLy8gPiBmYWxzZVxuICpcbiAqIEBwYXJhbSB7bWl4ZWR9IHZhbFxuICogQHJldHVybiB7Ym9vbH1cbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGlzQXJyYXkgfHwgZnVuY3Rpb24gKHZhbCkge1xuICByZXR1cm4gISEgdmFsICYmICdbb2JqZWN0IEFycmF5XScgPT0gc3RyLmNhbGwodmFsKTtcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJ2ZXJzaW9uXCI6IFwiXCJcbn1cbiIsIi8qKlxuICogRXBpY2VudGVyIEphdmFzY3JpcHQgbGlicmFyaWVzXG4gKiB2PCU9IHZlcnNpb24gJT5cbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9mb3Jpby9lcGljZW50ZXItanMtbGlic1xuICovXG5cbnZhciBGID0ge1xuICAgIHV0aWw6IHt9LFxuICAgIGZhY3Rvcnk6IHt9LFxuICAgIHRyYW5zcG9ydDoge30sXG4gICAgc3RvcmU6IHt9LFxuICAgIHNlcnZpY2U6IHt9LFxuICAgIG1hbmFnZXI6IHtcbiAgICAgICAgc3RyYXRlZ3k6IHt9XG4gICAgfSxcblxufTtcblxuRi51dGlsLnF1ZXJ5ID0gcmVxdWlyZSgnLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbkYudXRpbC5tYWtlU2VxdWVuY2UgPSByZXF1aXJlKCcuL3V0aWwvbWFrZS1zZXF1ZW5jZScpO1xuRi51dGlsLnJ1biA9IHJlcXVpcmUoJy4vdXRpbC9ydW4tdXRpbCcpO1xuRi51dGlsLmNsYXNzRnJvbSA9IHJlcXVpcmUoJy4vdXRpbC9pbmhlcml0Jyk7XG5cbkYuZmFjdG9yeS5UcmFuc3BvcnQgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5GLnRyYW5zcG9ydC5BamF4ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvYWpheC1odHRwLXRyYW5zcG9ydCcpO1xuXG5GLnNlcnZpY2UuVVJMID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xuRi5zZXJ2aWNlLkNvbmZpZyA9IHJlcXVpcmUoJy4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbkYuc2VydmljZS5SdW4gPSByZXF1aXJlKCcuL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRmlsZSA9IHJlcXVpcmUoJy4vc2VydmljZS9hZG1pbi1maWxlLXNlcnZpY2UnKTtcbkYuc2VydmljZS5WYXJpYWJsZXMgPSByZXF1aXJlKCcuL3NlcnZpY2UvdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRGF0YSA9IHJlcXVpcmUoJy4vc2VydmljZS9kYXRhLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuQXV0aCA9IHJlcXVpcmUoJy4vc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuV29ybGQgPSByZXF1aXJlKCcuL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5TdGF0ZSA9IHJlcXVpcmUoJy4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLlVzZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLk1lbWJlciA9IHJlcXVpcmUoJy4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Bc3NldCA9IHJlcXVpcmUoJy4vc2VydmljZS9hc3NldC1hcGktYWRhcHRlcicpO1xuXG5GLnN0b3JlLkNvb2tpZSA9IHJlcXVpcmUoJy4vc3RvcmUvY29va2llLXN0b3JlJyk7XG5GLmZhY3RvcnkuU3RvcmUgPSByZXF1aXJlKCcuL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcblxuRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvc2NlbmFyaW8tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLlJ1bk1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2F1dGgtbWFuYWdlcicpO1xuRi5tYW5hZ2VyLldvcmxkTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvd29ybGQtbWFuYWdlcicpO1xuXG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ2Fsd2F5cy1uZXcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvYWx3YXlzLW5ldy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5Wydjb25kaXRpb25hbC1jcmVhdGlvbiddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5LmlkZW50aXR5ID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9pZGVudGl0eS1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtcGVyc2lzdGVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLWluaXRpYWxpemVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpO1xuXG5GLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXInKTtcbkYuc2VydmljZS5DaGFubmVsID0gcmVxdWlyZSgnLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xuXG5GLnZlcnNpb24gPSAnPCU9IHZlcnNpb24gJT4nO1xuRi5hcGkgPSByZXF1aXJlKCcuL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuZ2xvYmFsLkYgPSBGO1xubW9kdWxlLmV4cG9ydHMgPSBGO1xuIiwiLyoqXG4qICMjIEF1dGhvcml6YXRpb24gTWFuYWdlclxuKlxuKiBUaGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIG1hbmFnZSB1c2VyIGF1dGhlbnRpY2F0aW9uIChsb2dnaW5nIGluIGFuZCBvdXQpIGFuZCBhdXRob3JpemF0aW9uIChrZWVwaW5nIHRyYWNrIG9mIHRva2Vucywgc2Vzc2lvbnMsIGFuZCBncm91cHMpIGZvciBwcm9qZWN0cy5cbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBpcyBtb3N0IHVzZWZ1bCBmb3IgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSB3aXRoIGFuIGFjY2VzcyBsZXZlbCBvZiBbQXV0aGVudGljYXRlZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2FjY2VzcykuIFRoZXNlIHByb2plY3RzIGFyZSBhY2Nlc3NlZCBieSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiBvbmUgb3IgbW9yZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS5cbipcbiogIyMjI1VzaW5nIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXJcbipcbiogVG8gdXNlIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZDpcbipcbiogICAgICAgdmFyIGF1dGhNZ3IgPSBuZXcgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKHtcbiogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgIHVzZXJOYW1lOiAnZW5kdXNlcjEnLFxuKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiogICAgICAgfSk7XG4qICAgICAgIGF1dGhNZ3IubG9naW4oKS50aGVuKGZ1bmN0aW9uICgpIHtcbiogICAgICAgICAgIGF1dGhNZ3IuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuKiAgICAgICB9KTtcbipcbipcbiogVGhlIGBvcHRpb25zYCBvYmplY3QgcGFzc2VkIHRvIHRoZSBgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKClgIGNhbGwgY2FuIGluY2x1ZGU6XG4qXG4qICAgKiBgYWNjb3VudGA6IFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICogYHVzZXJOYW1lYDogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLlxuKiAgICogYHBhc3N3b3JkYDogUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLlxuKiAgICogYHByb2plY3RgOiBUaGUgKipQcm9qZWN0IElEKiogZm9yIHRoZSBwcm9qZWN0IHRvIGxvZyB0aGlzIHVzZXIgaW50by4gT3B0aW9uYWwuXG4qICAgKiBgZ3JvdXBJZGA6IElkIG9mIHRoZSBncm91cCB0byB3aGljaCBgdXNlck5hbWVgIGJlbG9uZ3MuIFJlcXVpcmVkIGZvciBlbmQgdXNlcnMgaWYgdGhlIGBwcm9qZWN0YCBpcyBzcGVjaWZpZWQuXG4qXG4qIElmIHlvdSBwcmVmZXIgc3RhcnRpbmcgZnJvbSBhIHRlbXBsYXRlLCB0aGUgRXBpY2VudGVyIEpTIExpYnMgW0xvZ2luIENvbXBvbmVudF0oLi4vLi4vI2NvbXBvbmVudHMpIHVzZXMgdGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBhcyB3ZWxsLiBUaGlzIHNhbXBsZSBIVE1MIHBhZ2UgKGFuZCBhc3NvY2lhdGVkIENTUyBhbmQgSlMgZmlsZXMpIHByb3ZpZGVzIGEgbG9naW4gZm9ybSBmb3IgdGVhbSBtZW1iZXJzIGFuZCBlbmQgdXNlcnMgb2YgeW91ciBwcm9qZWN0LiBJdCBhbHNvIGluY2x1ZGVzIGEgZ3JvdXAgc2VsZWN0b3IgZm9yIGVuZCB1c2VycyB0aGF0IGFyZSBtZW1iZXJzIG9mIG11bHRpcGxlIGdyb3Vwcy5cbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBBdXRoQWRhcHRlciA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xudmFyIE1lbWJlckFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlcicpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIEJ1ZmZlciA9IHJlcXVpcmUoJ2J1ZmZlcicpLkJ1ZmZlcjtcbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4va2V5LW5hbWVzJyk7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBXaGVyZSB0byBzdG9yZSB1c2VyIGFjY2VzcyB0b2tlbnMgZm9yIHRlbXBvcmFyeSBhY2Nlc3MuIERlZmF1bHRzIHRvIHN0b3JpbmcgaW4gYSBjb29raWUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBzdG9yZTogeyBzeW5jaHJvbm91czogdHJ1ZSB9XG59O1xuXG52YXIgRVBJX0NPT0tJRV9LRVkgPSBrZXlOYW1lcy5FUElfQ09PS0lFX0tFWTtcbnZhciBFUElfU0VTU0lPTl9LRVkgPSBrZXlOYW1lcy5FUElfU0VTU0lPTl9LRVk7XG52YXIgc3RvcmU7XG52YXIgdG9rZW47XG52YXIgc2Vzc2lvbjtcblxuZnVuY3Rpb24gc2F2ZVNlc3Npb24odXNlckluZm8sIHN0b3JlKSB7XG4gICAgdmFyIHNlcmlhbGl6ZWQgPSBKU09OLnN0cmluZ2lmeSh1c2VySW5mbyk7XG4gICAgc3RvcmUuc2V0KEVQSV9TRVNTSU9OX0tFWSwgc2VyaWFsaXplZCk7XG5cbiAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgLy9qc2NzOmRpc2FibGVcbiAgICBzdG9yZS5zZXQoRVBJX0NPT0tJRV9LRVksIHVzZXJJbmZvLmF1dGhfdG9rZW4pO1xufVxuXG5mdW5jdGlvbiBnZXRTZXNzaW9uKHN0b3JlKSB7XG4gICAgdmFyIHNlc3Npb24gPSBzdG9yZS5nZXQoRVBJX1NFU1NJT05fS0VZKSB8fCAne30nO1xuICAgIHJldHVybiBKU09OLnBhcnNlKHNlc3Npb24pO1xufVxuXG5mdW5jdGlvbiBBdXRoTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZSh0aGlzLm9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB0aGlzLm9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICAvLyBudWxsIG1pZ2h0IHNwZWNpZmllZCB0byBkaXNhYmxlIHByb2plY3QgZmlsdGVyaW5nXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wcm9qZWN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5zdG9yZS5yb290ID09PSB1bmRlZmluZWQgJiYgdGhpcy5vcHRpb25zLmFjY291bnQgJiYgdGhpcy5vcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLnN0b3JlLnJvb3QgPSAnL2FwcC8nICsgdGhpcy5vcHRpb25zLmFjY291bnQgKyAnLycgKyB0aGlzLm9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB0aGlzLnN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHRoaXMub3B0aW9ucy5zdG9yZSk7XG4gICAgc2Vzc2lvbiA9IGdldFNlc3Npb24odGhpcy5zdG9yZSk7XG4gICAgdG9rZW4gPSB0aGlzLnN0b3JlLmdldChFUElfQ09PS0lFX0tFWSkgfHwgJyc7XG4gICAgLy9qc2hpbnQgY2FtZWxjYXNlOiBmYWxzZVxuICAgIC8vanNjczpkaXNhYmxlXG4gICAgdGhpcy5hdXRoQWRhcHRlciA9IG5ldyBBdXRoQWRhcHRlcih0aGlzLm9wdGlvbnMsIHsgdG9rZW46IHNlc3Npb24uYXV0aF90b2tlbiB9KTtcbn1cblxudmFyIF9maW5kVXNlckluR3JvdXAgPSBmdW5jdGlvbiAobWVtYmVycywgaWQpIHtcbiAgICBmb3IgKHZhciBqID0gMDsgajxtZW1iZXJzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIGlmIChtZW1iZXJzW2pdLnVzZXJJZCA9PT0gaWQpIHtcbiAgICAgICAgICAgIHJldHVybiBtZW1iZXJzW2pdO1xuICAgICAgICB9XG4gICAgfVxuXG5cbiAgICByZXR1cm4gbnVsbDtcbn07XG5cbkF1dGhNYW5hZ2VyLnByb3RvdHlwZSA9ICQuZXh0ZW5kKEF1dGhNYW5hZ2VyLnByb3RvdHlwZSwge1xuXG4gICAgLyoqXG4gICAgKiBMb2dzIHVzZXIgaW4uXG4gICAgKlxuICAgICogKipFeGFtcGxlKipcbiAgICAqXG4gICAgKiAgICAgICBhdXRoTWdyLmxvZ2luKHtcbiAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAqICAgICAgICAgICB1c2VyTmFtZTogJ2VuZHVzZXIxJyxcbiAgICAqICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJ1xuICAgICogICAgICAgfSlcbiAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbihzdGF0dXNPYmopIHtcbiAgICAqICAgICAgICAgICAgICAgLy8gaWYgZW5kdXNlcjEgYmVsb25ncyB0byBleGFjdGx5IG9uZSBncm91cFxuICAgICogICAgICAgICAgICAgICAvLyAob3IgaWYgdGhlIGxvZ2luKCkgY2FsbCBpcyBtb2RpZmllZCB0byBpbmNsdWRlIHRoZSBncm91cCBpZClcbiAgICAqICAgICAgICAgICAgICAgLy8gY29udGludWUgaGVyZVxuICAgICogICAgICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLmZhaWwoZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gbXVsdGlwbGUgZ3JvdXBzLFxuICAgICogICAgICAgICAgICAgICAvLyB0aGUgbG9naW4oKSBjYWxsIGZhaWxzXG4gICAgKiAgICAgICAgICAgICAgIC8vIGFuZCByZXR1cm5zIGFsbCBncm91cHMgb2Ygd2hpY2ggdGhlIHVzZXIgaXMgYSBtZW1iZXJcbiAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpIDwgc3RhdHVzT2JqLnVzZXJHcm91cHMubGVuZ3RoOyBpKyspIHtcbiAgICAqICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHN0YXR1c09iai51c2VyR3JvdXBzW2ldLm5hbWUsIHN0YXR1c09iai51c2VyR3JvdXBzW2ldLmdyb3VwSWQpO1xuICAgICogICAgICAgICAgICAgICB9XG4gICAgKiAgICAgICAgICAgfSk7XG4gICAgKlxuICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAqXG4gICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuIElmIG5vdCBwYXNzZWQgaW4gd2hlbiBjcmVhdGluZyBhbiBpbnN0YW5jZSBvZiB0aGUgbWFuYWdlciAoYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCksIHRoZXNlIG9wdGlvbnMgc2hvdWxkIGluY2x1ZGU6XG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMuYWNjb3VudGAgVGhlIGFjY291bnQgaWQgZm9yIHRoaXMgYHVzZXJOYW1lYC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciB0aGUgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMudXNlck5hbWVgIEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5wYXNzd29yZGAgUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnByb2plY3RgIChPcHRpb25hbCkgVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGUgcHJvamVjdCB0byBsb2cgdGhpcyB1c2VyIGludG8uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMuZ3JvdXBJZGAgVGhlIGlkIG9mIHRoZSBncm91cCB0byB3aGljaCBgdXNlck5hbWVgIGJlbG9uZ3MuIFJlcXVpcmVkIGZvciBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIGlmIHRoZSBgcHJvamVjdGAgaXMgc3BlY2lmaWVkIGFuZCBpZiB0aGUgZW5kIHVzZXJzIGFyZSBtZW1iZXJzIG9mIG11bHRpcGxlIFtncm91cHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvdGhlcndpc2Ugb3B0aW9uYWwuXG4gICAgKi9cbiAgICBsb2dpbjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgYWRhcHRlck9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHN1Y2Nlc3M6ICQubm9vcCwgZXJyb3I6ICQubm9vcCB9LCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICB2YXIgb3V0U3VjY2VzcyA9IGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgIHZhciBvdXRFcnJvciA9IGFkYXB0ZXJPcHRpb25zLmVycm9yO1xuICAgICAgICB2YXIgZ3JvdXBJZCA9IGFkYXB0ZXJPcHRpb25zLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGRlY29kZVRva2VuID0gZnVuY3Rpb24gKHRva2VuKSB7XG4gICAgICAgICAgICB2YXIgZW5jb2RlZCA9IHRva2VuLnNwbGl0KCcuJylbMV07XG4gICAgICAgICAgICB3aGlsZSAoZW5jb2RlZC5sZW5ndGggJSA0ICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgZW5jb2RlZCArPSAnPSc7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBkZWNvZGUgPSB3aW5kb3cuYXRvYiA/IHdpbmRvdy5hdG9iIDogZnVuY3Rpb24gKGVuY29kZWQpIHsgcmV0dXJuIG5ldyBCdWZmZXIoZW5jb2RlZCwgJ2Jhc2U2NCcpLnRvU3RyaW5nKCdhc2NpaScpOyB9O1xuXG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShkZWNvZGUoZW5jb2RlZCkpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBoYW5kbGVHcm91cEVycm9yID0gZnVuY3Rpb24gKG1lc3NhZ2UsIHN0YXR1c0NvZGUsIGRhdGEpIHtcbiAgICAgICAgICAgIC8vIGxvZ291dCB0aGUgdXNlciBzaW5jZSBpdCdzIGluIGFuIGludmFsaWQgc3RhdGUgd2l0aCBubyBncm91cCBzZWxlY3RlZFxuICAgICAgICAgICAgX3RoaXMubG9nb3V0KCkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdmFyIGVycm9yID0gJC5leHRlbmQodHJ1ZSwge30sIGRhdGEsIHsgc3RhdHVzVGV4dDogbWVzc2FnZSwgc3RhdHVzOiBzdGF0dXNDb2RlIH0pO1xuICAgICAgICAgICAgICAgICRkLnJlamVjdChlcnJvcik7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgaGFuZGxlU3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgLy9qc2hpbnQgY2FtZWxjYXNlOiBmYWxzZVxuICAgICAgICAgICAgLy9qc2NzOmRpc2FibGVcbiAgICAgICAgICAgIHRva2VuID0gcmVzcG9uc2UuYWNjZXNzX3Rva2VuO1xuICAgICAgICAgICAgdmFyIHVzZXJJbmZvID0gZGVjb2RlVG9rZW4odG9rZW4pO1xuICAgICAgICAgICAgdmFyIHVzZXJHcm91cE9wdHMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgYWRhcHRlck9wdGlvbnMsIHsgc3VjY2VzczogJC5ub29wLCB0b2tlbjogdG9rZW4gfSk7XG4gICAgICAgICAgICBfdGhpcy5nZXRVc2VyR3JvdXBzKHsgdXNlcklkOiB1c2VySW5mby51c2VyX2lkLCB0b2tlbjogdG9rZW4gfSwgdXNlckdyb3VwT3B0cykuZG9uZSggZnVuY3Rpb24gKG1lbWJlckluZm8pIHtcbiAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IHthdXRoOiByZXNwb25zZSwgdXNlcjogdXNlckluZm8sIHVzZXJHcm91cHM6IG1lbWJlckluZm8sIGdyb3VwU2VsZWN0aW9uOiB7fSB9O1xuXG4gICAgICAgICAgICAgICAgdmFyIHNlc3Npb25JbmZvID0ge1xuICAgICAgICAgICAgICAgICAgICAnYXV0aF90b2tlbic6IHRva2VuLFxuICAgICAgICAgICAgICAgICAgICAnYWNjb3VudCc6IGFkYXB0ZXJPcHRpb25zLmFjY291bnQsXG4gICAgICAgICAgICAgICAgICAgICdwcm9qZWN0JzogYWRhcHRlck9wdGlvbnMucHJvamVjdCxcbiAgICAgICAgICAgICAgICAgICAgJ3VzZXJJZCc6IHVzZXJJbmZvLnVzZXJfaWRcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIC8vIFRoZSBncm91cCBpcyBub3QgcmVxdWlyZWQgaWYgdGhlIHVzZXIgaXMgbm90IGxvZ2dpbmcgaW50byBhIHByb2plY3RcbiAgICAgICAgICAgICAgICBpZiAoIWFkYXB0ZXJPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgc2F2ZVNlc3Npb24oc2Vzc2lvbkluZm8sIF90aGlzLnN0b3JlKTtcbiAgICAgICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIGdyb3VwID0gbnVsbDtcbiAgICAgICAgICAgICAgICBpZiAobWVtYmVySW5mby5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgaGFuZGxlR3JvdXBFcnJvcignVGhlIHVzZXIgaGFzIG5vIGdyb3VwcyBhc3NvY2lhdGVkIGluIHRoaXMgYWNjb3VudCcsIDQwMSwgZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1lbWJlckluZm8ubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFNlbGVjdCB0aGUgb25seSBncm91cFxuICAgICAgICAgICAgICAgICAgICBncm91cCA9IG1lbWJlckluZm9bMF07XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZW1iZXJJbmZvLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGdyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBmaWx0ZXJlZEdyb3VwcyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAocmVzR3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzR3JvdXAuZ3JvdXBJZCA9PT0gZ3JvdXBJZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBmaWx0ZXJlZEdyb3Vwcy5sZW5ndGggPT09IDEgPyBmaWx0ZXJlZEdyb3Vwc1swXSA6IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGdyb3VwU2VsZWN0aW9uID0gZ3JvdXAuZ3JvdXBJZDtcbiAgICAgICAgICAgICAgICAgICAgZGF0YS5ncm91cFNlbGVjdGlvblthZGFwdGVyT3B0aW9ucy5wcm9qZWN0XSA9IGdyb3VwU2VsZWN0aW9uO1xuICAgICAgICAgICAgICAgICAgICB2YXIgc2Vzc2lvbkluZm9XaXRoR3JvdXAgPSAkLmV4dGVuZCh7fSwgc2Vzc2lvbkluZm8sIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICdncm91cElkJzogZ3JvdXAuZ3JvdXBJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICdncm91cE5hbWUnOiBncm91cC5uYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ2lzRmFjJzogX2ZpbmRVc2VySW5Hcm91cChncm91cC5tZW1iZXJzLCB1c2VySW5mby51c2VyX2lkKS5yb2xlID09PSAnZmFjaWxpdGF0b3InXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBzYXZlU2Vzc2lvbihzZXNzaW9uSW5mb1dpdGhHcm91cCwgX3RoaXMuc3RvcmUpO1xuICAgICAgICAgICAgICAgICAgICBvdXRTdWNjZXNzLmFwcGx5KHRoaXMsIFtkYXRhXSk7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUoZGF0YSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgaGFuZGxlR3JvdXBFcnJvcignVGhpcyB1c2VyIGlzIGFzc29jaWF0ZWQgd2l0aCBtb3JlIHRoYW4gb25lIGdyb3VwLiBQbGVhc2Ugc3BlY2lmeSBhIGdyb3VwIGlkIHRvIGxvZyBpbnRvIGFuZCB0cnkgYWdhaW4nLCA0MDMsIGRhdGEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pLmZhaWwoJGQucmVqZWN0KTtcbiAgICAgICAgfTtcblxuICAgICAgICBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzID0gaGFuZGxlU3VjY2VzcztcbiAgICAgICAgYWRhcHRlck9wdGlvbnMuZXJyb3IgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIGlmIChhZGFwdGVyT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgICAgICAgICAgLy8gVHJ5IHRvIGxvZ2luIGFzIGEgc3lzdGVtIHVzZXJcbiAgICAgICAgICAgICAgICBhZGFwdGVyT3B0aW9ucy5hY2NvdW50ID0gbnVsbDtcbiAgICAgICAgICAgICAgICBhZGFwdGVyT3B0aW9ucy5lcnJvciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgb3V0RXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVqZWN0KHJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgX3RoaXMuYXV0aEFkYXB0ZXIubG9naW4oYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgb3V0RXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICRkLnJlamVjdChyZXNwb25zZSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy5hdXRoQWRhcHRlci5sb2dpbihhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICogTG9ncyB1c2VyIG91dC5cbiAgICAqXG4gICAgKiAqKkV4YW1wbGUqKlxuICAgICpcbiAgICAqICAgICAgIGF1dGhNZ3IubG9nb3V0KCk7XG4gICAgKlxuICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAqXG4gICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgKi9cbiAgICBsb2dvdXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHsgdG9rZW46IHRva2VuIH0sIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIHJlbW92ZUNvb2tpZUZuID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBzdG9yZS5yZW1vdmUoRVBJX0NPT0tJRV9LRVksIGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgICAgIHN0b3JlLnJlbW92ZShFUElfU0VTU0lPTl9LRVksIGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgICAgIHRva2VuID0gJyc7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuYXV0aEFkYXB0ZXIubG9nb3V0KGFkYXB0ZXJPcHRpb25zKS5kb25lKHJlbW92ZUNvb2tpZUZuKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgZXhpc3RpbmcgdXNlciBhY2Nlc3MgdG9rZW4gaWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4uIE90aGVyd2lzZSwgbG9ncyB0aGUgdXNlciBpbiwgY3JlYXRpbmcgYSBuZXcgdXNlciBhY2Nlc3MgdG9rZW4sIGFuZCByZXR1cm5zIHRoZSBuZXcgdG9rZW4uIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VG9rZW4oKVxuICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZygnTXkgdG9rZW4gaXMgJywgdG9rZW4pO1xuICAgICAqICAgICAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICovXG4gICAgZ2V0VG9rZW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICBpZiAodG9rZW4pIHtcbiAgICAgICAgICAgICRkLnJlc29sdmUodG9rZW4pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5sb2dpbihodHRwT3B0aW9ucykudGhlbigkZC5yZXNvbHZlKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGFuIGFycmF5IG9mIGdyb3VwIHJlY29yZHMsIG9uZSBmb3IgZWFjaCBncm91cCBvZiB3aGljaCB0aGUgY3VycmVudCB1c2VyIGlzIGEgbWVtYmVyLiBFYWNoIGdyb3VwIHJlY29yZCBpbmNsdWRlcyB0aGUgZ3JvdXAgYG5hbWVgLCBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGBncm91cElkYC5cbiAgICAgKlxuICAgICAqIElmIHNvbWUgZW5kIHVzZXJzIGluIHlvdXIgcHJvamVjdCBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBncm91cHMsIHRoaXMgaXMgYSB1c2VmdWwgbWV0aG9kIHRvIGNhbGwgb24geW91ciBwcm9qZWN0J3MgbG9naW4gcGFnZS4gV2hlbiB0aGUgdXNlciBhdHRlbXB0cyB0byBsb2cgaW4sIHlvdSBjYW4gdXNlIHRoaXMgdG8gZGlzcGxheSB0aGUgZ3JvdXBzIG9mIHdoaWNoIHRoZSB1c2VyIGlzIG1lbWJlciwgYW5kIGhhdmUgdGhlIHVzZXIgc2VsZWN0IHRoZSBjb3JyZWN0IGdyb3VwIHRvIGxvZyBpbiB0byBmb3IgdGhpcyBzZXNzaW9uLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgLy8gZ2V0IGdyb3VwcyBmb3IgY3VycmVudCB1c2VyXG4gICAgICogICAgICB2YXIgc2Vzc2lvbk9iaiA9IGF1dGhNZ3IuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHsgdXNlcklkOiBzZXNzaW9uT2JqLnVzZXJJZCwgdG9rZW46IHNlc3Npb25PYmouYXV0aF90b2tlbiB9KVxuICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChncm91cHMpIHtcbiAgICAgKiAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpIDwgZ3JvdXBzLmxlbmd0aDsgaSsrKVxuICAgICAqICAgICAgICAgICAgICAgICAgeyBjb25zb2xlLmxvZyhncm91cHNbaV0ubmFtZSk7IH1cbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gZ2V0IGdyb3VwcyBmb3IgcGFydGljdWxhciB1c2VyXG4gICAgICogICAgICBhdXRoTWdyLmdldFVzZXJHcm91cHMoe3VzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHRva2VuOiBzYXZlZFByb2pBY2Nlc3NUb2tlbiB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBwYXJhbXNgIE9iamVjdCB3aXRoIGEgdXNlcklkIGFuZCB0b2tlbiBwcm9wZXJ0aWVzLlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIHVzZXJJZC4gSWYgbG9va2luZyB1cCBncm91cHMgZm9yIHRoZSBjdXJyZW50bHkgbG9nZ2VkIGluIHVzZXIsIHRoaXMgaXMgaW4gdGhlIHNlc3Npb24gaW5mb3JtYXRpb24uIE90aGVyd2lzZSwgcGFzcyBhIHN0cmluZy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy50b2tlbmAgVGhlIGF1dGhvcml6YXRpb24gY3JlZGVudGlhbHMgKGFjY2VzcyB0b2tlbikgdG8gdXNlIGZvciBjaGVja2luZyB0aGUgZ3JvdXBzIGZvciB0aGlzIHVzZXIuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBBIHRlYW0gbWVtYmVyJ3MgdG9rZW4gb3IgYSBwcm9qZWN0IGFjY2VzcyB0b2tlbiBjYW4gYWNjZXNzIGFsbCB0aGUgZ3JvdXBzIGZvciBhbGwgZW5kIHVzZXJzIGluIHRoZSB0ZWFtIG9yIHByb2plY3QuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFVzZXJHcm91cHM6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AgfSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgb3V0U3VjY2VzcyA9IGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3M7XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAvLyBUaGUgbWVtYmVyIEFQSSBpcyBhdCB0aGUgYWNjb3VudCBzY29wZSwgd2UgZmlsdGVyIGJ5IHByb2plY3RcbiAgICAgICAgICAgIGlmIChhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgbWVtYmVySW5mbyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdyb3VwLnByb2plY3QgPT09IGFkYXB0ZXJPcHRpb25zLnByb2plY3Q7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW21lbWJlckluZm9dKTtcbiAgICAgICAgICAgICRkLnJlc29sdmUobWVtYmVySW5mbyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIG1lbWJlckFkYXB0ZXIgPSBuZXcgTWVtYmVyQWRhcHRlcih7IHRva2VuOiBwYXJhbXMudG9rZW4gfSk7XG4gICAgICAgIG1lbWJlckFkYXB0ZXIuZ2V0R3JvdXBzRm9yVXNlcihwYXJhbXMsIGFkYXB0ZXJPcHRpb25zKS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgc2Vzc2lvbiBpbmZvcm1hdGlvbiBmb3IgdGhlIGN1cnJlbnQgdXNlciwgaW5jbHVkaW5nIHRoZSBgdXNlcklkYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGBncm91cElkYCwgYGdyb3VwTmFtZWAsIGBpc0ZhY2AgKHdoZXRoZXIgdGhlIGVuZCB1c2VyIGlzIGEgZmFjaWxpdGF0b3Igb2YgdGhpcyBncm91cCksIGFuZCBgYXV0aF90b2tlbmAgKHVzZXIgYWNjZXNzIHRva2VuKS5cbiAgICAgKlxuICAgICAqICpJbXBvcnRhbnQqOiBUaGlzIG1ldGhvZCBpcyBzeW5jaHJvbm91cy4gVGhlIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgcmV0dXJuZWQgaW1tZWRpYXRlbHkgaW4gYW4gb2JqZWN0OyBubyBjYWxsYmFja3Mgb3IgcHJvbWlzZXMgYXJlIG5lZWRlZC5cbiAgICAgKlxuICAgICAqIEJ5IGRlZmF1bHQsIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgc3RvcmVkIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLiBZb3UgY2FuIGNoYW5nZSB0aGlzIHdpdGggdGhlIGBzdG9yZWAgY29uZmlndXJhdGlvbiBvcHRpb24uXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgc2Vzc2lvbk9iaiA9IGF1dGhNZ3IuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICovXG4gICAgZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbzogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIGdldFNlc3Npb24odGhpcy5zdG9yZSwgb3B0aW9ucyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQXV0aE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDaGFubmVsID0gcmVxdWlyZSgnLi4vc2VydmljZS9jaGFubmVsLXNlcnZpY2UnKTtcblxuLyoqXG4gKiAjIyBDaGFubmVsIE1hbmFnZXJcbiAqXG4gKiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiBUaGUgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIGRlZmF1bHQgW2NvbWV0ZCBKYXZhU2NyaXB0IGxpYnJhcnldKGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvMi9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sKSwgYCQuY29tZXRkYC4gSXQgcHJvdmlkZXMgYSBmZXcgbmljZSBmZWF0dXJlcyB0aGF0IGAkLmNvbWV0ZGAgZG9lc24ndCwgaW5jbHVkaW5nOlxuICpcbiAqICogQXV0b21hdGljIHJlLXN1YnNjcmlwdGlvbiB0byBjaGFubmVscyBpZiB5b3UgbG9zZSB5b3VyIGNvbm5lY3Rpb25cbiAqICogT25saW5lIC8gT2ZmbGluZSBub3RpZmljYXRpb25zXG4gKiAqICdFdmVudHMnIGZvciBjb21ldGQgbm90aWZpY2F0aW9ucyAoaW5zdGVhZCBvZiBoYXZpbmcgdG8gbGlzdGVuIG9uIHNwZWNpZmljIG1ldGEgY2hhbm5lbHMpXG4gKlxuICogV2hpbGUgeW91IGNhbiB3b3JrIGRpcmVjdGx5IHdpdGggdGhlIENoYW5uZWwgTWFuYWdlciB0aHJvdWdoIE5vZGUuanMgKGZvciBleGFtcGxlLCBgcmVxdWlyZSgnbWFuYWdlci9jaGFubmVsLW1hbmFnZXInKWApIC0tIG9yIGV2ZW4gd29yayBkaXJlY3RseSB3aXRoIGAkLmNvbWV0ZGAgYW5kIEVwaWNlbnRlcidzIHVuZGVybHlpbmcgW1B1c2ggQ2hhbm5lbCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLykgLS0gbW9zdCBvZnRlbiBpdCB3aWxsIGJlIGVhc2llc3QgdG8gd29yayB3aXRoIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pLiBUaGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgdGhhdCBpbnN0YW50aWF0ZXMgYSBDaGFubmVsIE1hbmFnZXIgd2l0aCBFcGljZW50ZXItc3BlY2lmaWMgZGVmYXVsdHMuXG4gKlxuICogWW91J2xsIG5lZWQgdG8gaW5jbHVkZSB0aGUgYGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanNgIGxpYnJhcnkgaW4gYWRkaXRpb24gdG8gdGhlIGBlcGljZW50ZXIuanNgIGxpYnJhcnkgaW4geW91ciBwcm9qZWN0IHRvIHVzZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyLiAoU2VlIFtJbmNsdWRpbmcgRXBpY2VudGVyLmpzXSguLi8uLi8jaW5jbHVkZSkuKVxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyIGluIGNsaWVudC1zaWRlIEphdmFTY3JpcHQsIGluc3RhbnRpYXRlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pLCBnZXQgdGhlIGNoYW5uZWwsIHRoZW4gdXNlIHRoZSBjaGFubmVsJ3MgYHN1YnNjcmliZSgpYCBhbmQgYHB1Ymxpc2goKWAgbWV0aG9kcyB0byBzdWJzY3JpYmUgdG8gdG9waWNzIG9yIHB1Ymxpc2ggZGF0YSB0byB0b3BpY3MuXG4gKlxuICogICAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAqICAgICAgICB2YXIgY2hhbm5lbCA9IGNtLmdldENoYW5uZWwoKTtcbiAqXG4gKiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ3RvcGljJywgY2FsbGJhY2spO1xuICogICAgICAgIGNoYW5uZWwucHVibGlzaCgndG9waWMnLCB7IG15RGF0YTogMTAwIH0pO1xuICpcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciBpbnN0YW50aWF0aW5nIGEgQ2hhbm5lbCBNYW5hZ2VyIGluY2x1ZGU6XG4gKlxuICogKiBgb3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyLiBCZXNpZGVzIHRoZSBjb21tb24gb3B0aW9ucyBsaXN0ZWQgaGVyZSwgc2VlIGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCBmb3Igb3RoZXIgc3VwcG9ydGVkIG9wdGlvbnMuXG4gKiAqIGBvcHRpb25zLnVybGAgVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gKiAqIGBvcHRpb25zLndlYnNvY2tldEVuYWJsZWRgIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlIChib29sZWFuKS5cbiAqICogYG9wdGlvbnMuY2hhbm5lbGAgT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgQ2hhbm5lbCBTZXJ2aWNlLiBTZWUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykgZm9yIGRldGFpbHMuXG4gKlxuICovXG52YXIgQ2hhbm5lbE1hbmFnZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIGlmICghJC5jb21ldGQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb21ldGQgbGlicmFyeSBub3QgZm91bmQuIFBsZWFzZSBpbmNsdWRlIGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanMnKTtcbiAgICB9XG4gICAgaWYgKCFvcHRpb25zIHx8ICFvcHRpb25zLnVybCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGFuIHVybCBmb3IgdGhlIGNvbWV0ZCBzZXJ2ZXInKTtcbiAgICB9XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgQ29tZXRkIGVuZHBvaW50IFVSTC5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVybDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBsb2cgbGV2ZWwgZm9yIHRoZSBjaGFubmVsIChsb2dzIHRvIGNvbnNvbGUpLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbG9nTGV2ZWw6ICdpbmZvJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogV2hldGhlciB3ZWJzb2NrZXQgc3VwcG9ydCBpcyBhY3RpdmUuIERlZmF1bHRzIHRvIGBmYWxzZWA7IEVwaWNlbnRlciBkb2Vzbid0IGN1cnJlbnRseSBzdXBwb3J0IGNvbW11bmljYXRpb24gdGhyb3VnaCB3ZWJzb2NrZXRzLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIHdlYnNvY2tldEVuYWJsZWQ6IGZhbHNlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBJZiBmYWxzZSBlYWNoIGluc3RhbmNlIG9mIENoYW5uZWwgd2lsbCBoYXZlIGEgc2VwYXJhdGUgY29tZXRkIGNvbm5lY3Rpb24gdG8gc2VydmVyLCB3aGljaCBjb3VsZCBiZSBub2lzeS4gU2V0IHRvIHRydWUgdG8gcmUtdXNlIHRoZSBzYW1lIGNvbm5lY3Rpb24gYWNyb3NzIGluc3RhbmNlcy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBzaGFyZUNvbm5lY3Rpb246IGZhbHNlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPdGhlciBkZWZhdWx0cyB0byBwYXNzIG9uIHRvIGluc3RhbmNlcyBvZiB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSwgd2hpY2ggYXJlIGNyZWF0ZWQgdGhyb3VnaCBgZ2V0Q2hhbm5lbCgpYC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIGNoYW5uZWw6IHtcblxuICAgICAgICB9XG4gICAgfTtcbiAgICB2YXIgZGVmYXVsdENvbWV0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG5cbiAgICBpZiAoZGVmYXVsdENvbWV0T3B0aW9ucy5zaGFyZUNvbm5lY3Rpb24gJiYgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQpIHtcbiAgICAgICAgdGhpcy5jb21ldGQgPSBDaGFubmVsTWFuYWdlci5wcm90b3R5cGUuX2NvbWV0ZDtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuICAgIHZhciBjb21ldGQgPSBuZXcgJC5Db21ldGQoKTtcbiAgICBDaGFubmVsTWFuYWdlci5wcm90b3R5cGUuX2NvbWV0ZCA9IGNvbWV0ZDtcblxuICAgIGNvbWV0ZC53ZWJzb2NrZXRFbmFibGVkID0gZGVmYXVsdENvbWV0T3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkO1xuXG4gICAgdGhpcy5pc0Nvbm5lY3RlZCA9IGZhbHNlO1xuICAgIHZhciBjb25uZWN0aW9uQnJva2VuID0gZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyKCdkaXNjb25uZWN0JywgbWVzc2FnZSk7XG4gICAgfTtcbiAgICB2YXIgY29ubmVjdGlvblN1Y2NlZWRlZCA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIG1lID0gdGhpcztcblxuICAgIGNvbWV0ZC5jb25maWd1cmUoZGVmYXVsdENvbWV0T3B0aW9ucyk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Nvbm5lY3QnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICB2YXIgd2FzQ29ubmVjdGVkID0gdGhpcy5pc0Nvbm5lY3RlZDtcbiAgICAgICAgdGhpcy5pc0Nvbm5lY3RlZCA9IChtZXNzYWdlLnN1Y2Nlc3NmdWwgPT09IHRydWUpO1xuICAgICAgICBpZiAoIXdhc0Nvbm5lY3RlZCAmJiB0aGlzLmlzQ29ubmVjdGVkKSB7IC8vQ29ubmVjdGluZyBmb3IgdGhlIGZpcnN0IHRpbWVcbiAgICAgICAgICAgIGNvbm5lY3Rpb25TdWNjZWVkZWQuY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfSBlbHNlIGlmICh3YXNDb25uZWN0ZWQgJiYgIXRoaXMuaXNDb25uZWN0ZWQpIHsgLy9Pbmx5IHRocm93IGRpc2Nvbm5lY3RlZCBtZXNzYWdlIGZybyB0aGUgZmlyc3QgZGlzY29ubmVjdCwgbm90IG9uY2UgcGVyIHRyeVxuICAgICAgICAgICAgY29ubmVjdGlvbkJyb2tlbi5jYWxsKHRoaXMsIG1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgfS5iaW5kKHRoaXMpKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvZGlzY29ubmVjdCcsIGNvbm5lY3Rpb25Ccm9rZW4pO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9oYW5kc2hha2UnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICBpZiAobWVzc2FnZS5zdWNjZXNzZnVsKSB7XG4gICAgICAgICAgICAvL2h0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHRfc3Vic2NyaWJlLmh0bWwjamF2YXNjcmlwdF9zdWJzY3JpYmVfbWV0YV9jaGFubmVsc1xuICAgICAgICAgICAgLy8gXiBcImR5bmFtaWMgc3Vic2NyaXB0aW9ucyBhcmUgY2xlYXJlZCAobGlrZSBhbnkgb3RoZXIgc3Vic2NyaXB0aW9uKSBhbmQgdGhlIGFwcGxpY2F0aW9uIG5lZWRzIHRvIGZpZ3VyZSBvdXQgd2hpY2ggZHluYW1pYyBzdWJzY3JpcHRpb24gbXVzdCBiZSBwZXJmb3JtZWQgYWdhaW5cIlxuICAgICAgICAgICAgY29tZXRkLmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAkKG1lLmN1cnJlbnRTdWJzY3JpcHRpb25zKS5lYWNoKGZ1bmN0aW9uIChpbmRleCwgc3Vicykge1xuICAgICAgICAgICAgICAgICAgICBjb21ldGQucmVzdWJzY3JpYmUoc3Vicyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy9PdGhlciBpbnRlcmVzdGluZyBldmVudHMgZm9yIHJlZmVyZW5jZVxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvc3Vic2NyaWJlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcignc3Vic2NyaWJlJywgbWVzc2FnZSk7XG4gICAgfSk7XG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS91bnN1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3Vuc3Vic2NyaWJlJywgbWVzc2FnZSk7XG4gICAgfSk7XG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9wdWJsaXNoJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcigncHVibGlzaCcsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWNjZXNzZnVsJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcignZXJyb3InLCBtZXNzYWdlKTtcbiAgICB9KTtcblxuICAgIGNvbWV0ZC5oYW5kc2hha2UoKTtcblxuICAgIHRoaXMuY29tZXRkID0gY29tZXRkO1xufTtcblxuXG5DaGFubmVsTWFuYWdlci5wcm90b3R5cGUgPSAkLmV4dGVuZChDaGFubmVsTWFuYWdlci5wcm90b3R5cGUsIHtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW5kIHJldHVybnMgYSBjaGFubmVsLCB0aGF0IGlzLCBhbiBpbnN0YW5jZSBvZiBhIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gICAgICpcbiAgICAgKiAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAgICAgKiAgICAgIGNoYW5uZWwucHVibGlzaCgndG9waWMnLCB7IG15RGF0YTogMTAwIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge09iamVjdHxTdHJpbmd9IGBvcHRpb25zYCAoT3B0aW9uYWwpIElmIHN0cmluZywgYXNzdW1lZCB0byBiZSB0aGUgYmFzZSBjaGFubmVsIHVybC4gSWYgb2JqZWN0LCBhc3N1bWVkIHRvIGJlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNvbnN0cnVjdG9yLlxuICAgICAqL1xuICAgIGdldENoYW5uZWw6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIC8vSWYgeW91IGp1c3Qgd2FudCB0byBwYXNzIGluIGEgc3RyaW5nXG4gICAgICAgIGlmIChvcHRpb25zICYmICEkLmlzUGxhaW5PYmplY3Qob3B0aW9ucykpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSB7XG4gICAgICAgICAgICAgICAgYmFzZTogb3B0aW9uc1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgICAgICB0cmFuc3BvcnQ6IHRoaXMuY29tZXRkXG4gICAgICAgIH07XG4gICAgICAgIHZhciBjaGFubmVsID0gbmV3IENoYW5uZWwoJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy5jaGFubmVsLCBkZWZhdWx0cywgb3B0aW9ucykpO1xuXG5cbiAgICAgICAgLy9XcmFwIHN1YnMgYW5kIHVuc3VicyBzbyB3ZSBjYW4gdXNlIGl0IHRvIHJlLWF0dGFjaCBoYW5kbGVycyBhZnRlciBiZWluZyBkaXNjb25uZWN0ZWRcbiAgICAgICAgdmFyIHN1YnMgPSBjaGFubmVsLnN1YnNjcmliZTtcbiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgc3ViaWQgPSBzdWJzLmFwcGx5KGNoYW5uZWwsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zICA9IHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuY29uY2F0KHN1YmlkKTtcbiAgICAgICAgICAgIHJldHVybiBzdWJpZDtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG5cbiAgICAgICAgdmFyIHVuc3VicyA9IGNoYW5uZWwudW5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwudW5zdWJzY3JpYmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcmVtb3ZlZCA9IHVuc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnNbaV0uaWQgPT09IHJlbW92ZWQuaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHJlbW92ZWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICpcbiAgICAgKiBTdXBwb3J0ZWQgZXZlbnRzIGFyZTogYGNvbm5lY3RgLCBgZGlzY29ubmVjdGAsIGBzdWJzY3JpYmVgLCBgdW5zdWJzY3JpYmVgLCBgcHVibGlzaGAsIGBlcnJvcmAuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqL1xuICAgIG9uOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vbi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdG9wIGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqL1xuICAgIG9mZjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub2ZmLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZXZlbnRzIGFuZCBleGVjdXRlIGhhbmRsZXJzLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqL1xuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBDaGFubmVsTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiAjIyBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlIEVwaWNlbnRlciBwbGF0Zm9ybSBwcm92aWRlcyBhIHB1c2ggY2hhbm5lbCwgd2hpY2ggYWxsb3dzIHlvdSB0byBwdWJsaXNoIGFuZCBzdWJzY3JpYmUgdG8gbWVzc2FnZXMgd2l0aGluIGEgW3Byb2plY3RdKC4uLy4uLy4uL2dsb3NzYXJ5LyNwcm9qZWN0cyksIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcyksIG9yIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS4gVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIGFyb3VuZCB0aGUgKG1vcmUgZ2VuZXJpYykgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLyksIHRvIGluc3RhbnRpYXRlIGl0IHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLiBJZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gaW5jbHVkaW5nIGEgbm90aWZpY2F0aW9uIG9yIGNoYXQgZmVhdHVyZSBpbiB5b3VyIHByb2plY3QsIHVzaW5nIGFuIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgcHJvYmFibHkgdGhlIGVhc2llc3Qgd2F5IHRvIGdldCBzdGFydGVkLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIuIFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLlxuICpcbiAqIFRvIHVzZSB0aGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcjogaW5zdGFudGlhdGUgaXQsIGdldCB0aGUgY2hhbm5lbCBvZiB0aGUgc2NvcGUgeW91IHdhbnQgKFt1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCksIG9yIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykpLCB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgdmFyIGdjID0gY20uZ2V0R3JvdXBDaGFubmVsKCk7XG4gKiAgICAgZ2Muc3Vic2NyaWJlKCdicm9hZGNhc3RzJywgY2FsbGJhY2spO1xuICpcbiAqIEZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gRXBpY2VudGVyJ3MgcHVzaCBjaGFubmVsLCBzZWUgdGhlIGludHJvZHVjdG9yeSBub3RlcyBvbiB0aGUgW1B1c2ggQ2hhbm5lbCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLykgcGFnZS5cbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGluY2x1ZGU6XG4gKlxuICogKiBgc2VydmVyYCBPYmplY3Qgd2l0aCBkZXRhaWxzIGFib3V0IHRoZSBFcGljZW50ZXIgcHJvamVjdCBmb3IgdGhpcyBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGluc3RhbmNlLlxuICogKiBgc2VydmVyLmFjY291bnRgIFRoZSBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBzZXJ2ZXIucHJvamVjdGAgRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKi9cblxudmFyIENoYW5uZWxNYW5hZ2VyID0gcmVxdWlyZSgnLi9jaGFubmVsLW1hbmFnZXInKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi91dGlsL2luaGVyaXQnKTtcbnZhciB1cmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcblxudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIHNlc3Npb24gPSBuZXcgQXV0aE1hbmFnZXIoKTtcbnZhciBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yID0gZnVuY3Rpb24gKHZhbHVlLCBzZXNzaW9uS2V5TmFtZSwgc2V0dGluZ3MpIHtcbiAgICBpZiAoIXZhbHVlKSB7XG4gICAgICAgIHZhciB1c2VySW5mbyA9IHNlc3Npb24uZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICBpZiAoc2V0dGluZ3MgJiYgc2V0dGluZ3Nbc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIGlmICh1c2VySW5mb1tzZXNzaW9uS2V5TmFtZV0pIHtcbiAgICAgICAgICAgIHZhbHVlID0gdXNlckluZm9bc2Vzc2lvbktleU5hbWVdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHNlc3Npb25LZXlOYW1lICsgJyBub3QgZm91bmQuIFBsZWFzZSBsb2ctaW4gYWdhaW4sIG9yIHNwZWNpZnkgJyArIHNlc3Npb25LZXlOYW1lICsgJyBleHBsaWNpdGx5Jyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHZhbHVlO1xufTtcbnZhciBfX3N1cGVyID0gQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlO1xudmFyIEVwaWNlbnRlckNoYW5uZWxNYW5hZ2VyID0gY2xhc3NGcm9tKENoYW5uZWxNYW5hZ2VyLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciB1c2VySW5mbyA9IHNlc3Npb24uZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuXG4gICAgICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgICAgIGFjY291bnQ6IHVzZXJJbmZvLmFjY291bnQsXG4gICAgICAgICAgICBwcm9qZWN0OiB1c2VySW5mby5wcm9qZWN0LFxuICAgICAgICB9O1xuICAgICAgICB2YXIgZGVmYXVsdENvbWV0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgdXNlckluZm8sIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciB1cmxPcHRzID0gdXJsU2VydmljZShkZWZhdWx0Q29tZXRPcHRpb25zLnNlcnZlcik7XG4gICAgICAgIGlmICghZGVmYXVsdENvbWV0T3B0aW9ucy51cmwpIHtcbiAgICAgICAgICAgIC8vRGVmYXVsdCBlcGljZW50ZXIgY29tZXRkIGVuZHBvaW50XG4gICAgICAgICAgICBkZWZhdWx0Q29tZXRPcHRpb25zLnVybCA9IHVybE9wdHMucHJvdG9jb2wgKyAnOi8vJyArIHVybE9wdHMuaG9zdCArICcvY2hhbm5lbC9zdWJzY3JpYmUnO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5vcHRpb25zID0gZGVmYXVsdENvbWV0T3B0aW9ucztcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBkZWZhdWx0Q29tZXRPcHRpb25zKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykuIFRoZSBncm91cCBtdXN0IGV4aXN0IGluIHRoZSBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdCBwcm92aWRlZC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBubyBub3RpZmljYXRpb25zIGZyb20gRXBpY2VudGVyIG9uIHRoaXMgY2hhbm5lbDsgYWxsIG1lc3NhZ2VzIGFyZSB1c2VyLW9yaWdpbmF0ZWQuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIGdjID0gY20uZ2V0R3JvdXBDaGFubmVsKCk7XG4gICAgICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRvIGJyb2FkY2FzdCB0by4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0R3JvdXBDaGFubmVsOiBmdW5jdGlvbiAoZ3JvdXBOYW1lKSB7XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJyk7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvZ3JvdXAnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWVdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgZ2l2ZW4gW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLlxuICAgICAqXG4gICAgICogVGhpcyBpcyB0eXBpY2FsbHkgdXNlZCB0b2dldGhlciB3aXRoIHRoZSBbV29ybGQgTWFuYWdlcl0oLi4vd29ybGQtbWFuYWdlcikuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB3b3JsZENoYW5uZWwgPSBjbS5nZXRXb3JsZENoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgd29ybGRDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB3b3JsZGAgVGhlIHdvcmxkIG9iamVjdCBvciBpZC5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgR3JvdXAgdGhlIHdvcmxkIGV4aXN0cyBpbi4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0V29ybGRDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuXG4gICAgICAgIHZhciBiYXNlVG9waWMgPSBbJy93b3JsZCcsIGFjY291bnQsIHByb2plY3QsIGdyb3VwTmFtZSwgd29ybGRpZF0uam9pbignLycpO1xuICAgICAgICByZXR1cm4gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBjdXJyZW50IFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpbiB0aGF0IHVzZXIncyBjdXJyZW50IFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLiBOb3RlIHRoYXQgdGhpcyBjaGFubmVsIG9ubHkgZ2V0cyBub3RpZmljYXRpb25zIGZvciB3b3JsZHMgY3VycmVudGx5IGluIG1lbW9yeS4gKFNlZSBtb3JlIGJhY2tncm91bmQgb24gW3BlcnNpc3RlbmNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UpLilcbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAqICAgICAgICAgcnVuOiB7IG1vZGVsOiAnbW9kZWwuZXFuJyB9XG4gICAgICogICAgIH0pO1xuICAgICAqICAgICB3b3JsZE1hbmFnZXIuZ2V0Q3VycmVudFdvcmxkKCkudGhlbihmdW5jdGlvbiAod29ybGRPYmplY3QsIHdvcmxkQWRhcHRlcikge1xuICAgICAqICAgICAgICAgdmFyIHVzZXJDaGFubmVsID0gY20uZ2V0VXNlckNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgdXNlckNoYW5uZWwuc3Vic2NyaWJlKCcnLCBmdW5jdGlvbiAoZGF0YSkge1xuICAgICAqICAgICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgICAqICAgICAgICAgfSk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFdvcmxkIG9iamVjdCBvciBpZC5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgdXNlcmAgKE9wdGlvbmFsKSBVc2VyIG9iamVjdCBvciBpZC4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCB1c2VyIGlkIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgR3JvdXAgdGhlIHdvcmxkIGV4aXN0cyBpbi4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0VXNlckNoYW5uZWw6IGZ1bmN0aW9uICh3b3JsZCwgdXNlciwgZ3JvdXBOYW1lKSB7XG4gICAgICAgIHZhciB3b3JsZGlkID0gKCQuaXNQbGFpbk9iamVjdCh3b3JsZCkgJiYgd29ybGQuaWQpID8gd29ybGQuaWQgOiB3b3JsZDtcbiAgICAgICAgaWYgKCF3b3JsZGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgd29ybGQgaWQnKTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgdXNlcmlkID0gKCQuaXNQbGFpbk9iamVjdCh1c2VyKSAmJiB1c2VyLmlkKSA/IHVzZXIuaWQgOiB1c2VyO1xuICAgICAgICB1c2VyaWQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKHVzZXJpZCwgJ3VzZXJJZCcpO1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScpO1xuXG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvdXNlcnMnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWQsIHVzZXJpZF0uam9pbignLycpO1xuICAgICAgICByZXR1cm4gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgdGhhdCBhdXRvbWF0aWNhbGx5IHRyYWNrcyB0aGUgcHJlc2VuY2Ugb2YgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGF0IGlzLCB3aGV0aGVyIHRoZSBlbmQgdXNlciBpcyBjdXJyZW50bHkgb25saW5lIGluIHRoaXMgZ3JvdXAgYW5kIHdvcmxkLiBOb3RpZmljYXRpb25zIGFyZSBhdXRvbWF0aWNhbGx5IHNlbnQgd2hlbiB0aGUgZW5kIHVzZXIgY29tZXMgb25saW5lLCBhbmQgd2hlbiB0aGUgZW5kIHVzZXIgZ29lcyBvZmZsaW5lIChub3QgcHJlc2VudCBmb3IgbW9yZSB0aGFuIDIgbWludXRlcykuIFVzZWZ1bCBpbiBtdWx0aXBsYXllciBnYW1lcyBmb3IgbGV0dGluZyBlYWNoIGVuZCB1c2VyIGtub3cgd2hldGhlciBvdGhlciB1c2VycyBpbiB0aGVpciBzaGFyZWQgd29ybGQgYXJlIGFsc28gb25saW5lLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgICogICAgIH0pO1xuICAgICAqICAgICB3b3JsZE1hbmFnZXIuZ2V0Q3VycmVudFdvcmxkKCkudGhlbihmdW5jdGlvbiAod29ybGRPYmplY3QsIHdvcmxkU2VydmljZSkge1xuICAgICAqICAgICAgICAgdmFyIHByZXNlbmNlQ2hhbm5lbCA9IGNtLmdldFByZXNlbmNlQ2hhbm5lbCh3b3JsZE9iamVjdCk7XG4gICAgICogICAgICAgICBwcmVzZW5jZUNoYW5uZWwub24oJ3ByZXNlbmNlJywgZnVuY3Rpb24gKGV2dCwgbm90aWZpY2F0aW9uKSB7XG4gICAgICogICAgICAgICAgICAgIGNvbnNvbGUubG9nKG5vdGlmaWNhdGlvbi5vbmxpbmUsIG5vdGlmaWNhdGlvbi51c2VySWQpO1xuICAgICAqICAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJpZGAgKE9wdGlvbmFsKSBVc2VyIG9iamVjdCBvciBpZC4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCB1c2VyIGlkIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgR3JvdXAgdGhlIHdvcmxkIGV4aXN0cyBpbi4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0UHJlc2VuY2VDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXJpZCwgZ3JvdXBOYW1lKSB7XG4gICAgICAgIHZhciB3b3JsZGlkID0gKCQuaXNQbGFpbk9iamVjdCh3b3JsZCkgJiYgd29ybGQuaWQpID8gd29ybGQuaWQgOiB3b3JsZDtcbiAgICAgICAgaWYgKCF3b3JsZGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgd29ybGQgaWQnKTtcbiAgICAgICAgfVxuICAgICAgICB1c2VyaWQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKHVzZXJpZCwgJ3VzZXJJZCcpO1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScpO1xuXG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvdXNlcnMnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcblxuICAgICAgICB2YXIgbGFzdFBpbmdUaW1lID0geyB9O1xuXG4gICAgICAgIHZhciBQSU5HX0lOVEVSVkFMID0gNjAwMDtcbiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIGZ1bmN0aW9uIChub3RpZmljYXRpb24pIHtcbiAgICAgICAgICAgIHZhciBpbmNvbWluZ1VzZXJJZCA9IG5vdGlmaWNhdGlvbi5kYXRhLnVzZXI7XG4gICAgICAgICAgICBpZiAoIWxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gJiYgaW5jb21pbmdVc2VySWQgIT09IHVzZXJpZCkge1xuICAgICAgICAgICAgICAgIGNoYW5uZWwudHJpZ2dlci5jYWxsKGNoYW5uZWwsICdwcmVzZW5jZScsIHsgdXNlcklkOiBpbmNvbWluZ1VzZXJJZCwgb25saW5lOiB0cnVlIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2luY29taW5nVXNlcklkXSA9IChuZXcgRGF0ZSgpKS52YWx1ZU9mKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHNldEludGVydmFsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGNoYW5uZWwucHVibGlzaCgnaW50ZXJuYWwtcGluZy1jaGFubmVsJywgeyB1c2VyOiB1c2VyaWQgfSk7XG5cbiAgICAgICAgICAgICQuZWFjaChsYXN0UGluZ1RpbWUsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vdyA9IChuZXcgRGF0ZSgpKS52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgaWYgKHZhbHVlICYmIHZhbHVlICsgKFBJTkdfSU5URVJWQUwgKiAyKSA8IG5vdykge1xuICAgICAgICAgICAgICAgICAgICBsYXN0UGluZ1RpbWVba2V5XSA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIGNoYW5uZWwudHJpZ2dlci5jYWxsKGNoYW5uZWwsICdwcmVzZW5jZScsIHsgdXNlcklkOiBrZXksIG9ubGluZTogZmFsc2UgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIFBJTkdfSU5URVJWQUwpO1xuXG4gICAgICAgIHJldHVybiBjaGFubmVsO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgZ2l2ZW4gY29sbGVjdGlvbi4gKFRoZSBjb2xsZWN0aW9uIG5hbWUgaXMgc3BlY2lmaWVkIGluIHRoZSBgcm9vdGAgYXJndW1lbnQgd2hlbiB0aGUgW0RhdGEgU2VydmljZV0oLi4vZGF0YS1hcGktc2VydmljZS8pIGlzIGluc3RhbnRpYXRlZC4pIE11c3QgYmUgb25lIG9mIHRoZSBjb2xsZWN0aW9ucyBpbiB0aGlzIGFjY291bnQgKHRlYW0pIGFuZCBwcm9qZWN0LlxuICAgICAqXG4gICAgICogVGhlcmUgYXJlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIGZyb20gRXBpY2VudGVyIG9uIHRoaXMgY2hhbm5lbCB3aGVuIGRhdGEgaXMgY3JlYXRlZCwgdXBkYXRlZCwgb3IgZGVsZXRlZCBpbiB0aGlzIGNvbGxlY3Rpb24uIFNlZSBtb3JlIG9uIFthdXRvbWF0aWMgbWVzc2FnZXMgdG8gdGhlIGRhdGEgY2hhbm5lbF0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvI2RhdGEtbWVzc2FnZXMpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciBnYyA9IGNtLmdldERhdGFDaGFubmVsKCdzdXJ2ZXktcmVzcG9uc2VzJyk7XG4gICAgICogICAgIGdjLnN1YnNjcmliZSgnJywgZnVuY3Rpb24oZGF0YSwgbWV0YSkge1xuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gbWV0YS5kYXRlIGlzIHRpbWUgb2YgY2hhbmdlLFxuICAgICAqICAgICAgICAgIC8vIG1ldGEuc3ViVHlwZSBpcyB0aGUga2luZCBvZiBjaGFuZ2U6IG5ldywgdXBkYXRlLCBvciBkZWxldGVcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnBhdGggaXMgdGhlIGZ1bGwgcGF0aCB0byB0aGUgY2hhbmdlZCBkYXRhXG4gICAgICogICAgICAgICAgY29uc29sZS5sb2cobWV0YSk7XG4gICAgICogICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBjb2xsZWN0aW9uYCBOYW1lIG9mIGNvbGxlY3Rpb24gd2hvc2UgYXV0b21hdGljIG5vdGlmaWNhdGlvbnMgeW91IHdhbnQgdG8gcmVjZWl2ZS5cbiAgICAgKi9cbiAgICBnZXREYXRhQ2hhbm5lbDogZnVuY3Rpb24gKGNvbGxlY3Rpb24pIHtcbiAgICAgICAgaWYgKCFjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgY29sbGVjdGlvbiB0byBsaXN0ZW4gb24uJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvZGF0YScsIGFjY291bnQsIHByb2plY3QsIGNvbGxlY3Rpb25dLmpvaW4oJy8nKTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcblxuICAgICAgICAvL1RPRE86IEZpeCBhZnRlciBFcGljZW50ZXIgYnVnIGlzIHJlc29sdmVkXG4gICAgICAgIHZhciBvbGRzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKHRvcGljLCBjYWxsYmFjaywgY29udGV4dCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNhbGxiYWNrV2l0aENsZWFuRGF0YSA9IGZ1bmN0aW9uIChwYXlsb2FkKSB7XG4gICAgICAgICAgICAgICAgdmFyIG1ldGEgPSB7XG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IHBheWxvYWQuY2hhbm5lbCxcbiAgICAgICAgICAgICAgICAgICAgc3ViVHlwZTogcGF5bG9hZC5kYXRhLnN1YlR5cGUsXG4gICAgICAgICAgICAgICAgICAgIGRhdGU6IHBheWxvYWQuZGF0YS5kYXRlXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgYWN0dWFsRGF0YSA9IHBheWxvYWQuZGF0YS5kYXRhO1xuICAgICAgICAgICAgICAgIGlmIChhY3R1YWxEYXRhLmRhdGEpIHsgLy9EZWxldGUgbm90aWZpY2F0aW9ucyBhcmUgb25lIGRhdGEtbGV2ZWwgYmVoaW5kIG9mIGNvdXJzZVxuICAgICAgICAgICAgICAgICAgICBhY3R1YWxEYXRhID0gYWN0dWFsRGF0YS5kYXRhO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNhbGxiYWNrLmNhbGwoY29udGV4dCwgYWN0dWFsRGF0YSwgbWV0YSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuIG9sZHN1YnMuY2FsbChjaGFubmVsLCB0b3BpYywgY2FsbGJhY2tXaXRoQ2xlYW5EYXRhLCBjb250ZXh0LCBvcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBFcGljZW50ZXJDaGFubmVsTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgRVBJX0NPT0tJRV9LRVk6ICdlcGljZW50ZXIucHJvamVjdC50b2tlbicsXG4gICAgRVBJX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLnVzZXIuc2Vzc2lvbicsXG4gICAgU1RSQVRFR1lfU0VTU0lPTl9LRVk6ICdlcGljZW50ZXItc2NlbmFyaW8nXG59OyIsIi8qKlxuKiAjIyBSdW4gTWFuYWdlclxuKlxuKiBUaGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGFjY2VzcyB0byBydW5zIGZvciB5b3VyIHByb2plY3QuIFRoaXMgYWxsb3dzIHlvdSB0byByZWFkIGFuZCB1cGRhdGUgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy4gQWRkaXRpb25hbGx5LCB0aGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGNvbnRyb2wgb3ZlciBydW4gY3JlYXRpb24gZGVwZW5kaW5nIG9uIHJ1biBzdGF0ZXMuIFNwZWNpZmljYWxseSwgeW91IGNhbiBzZWxlY3QgW3J1biBjcmVhdGlvbiBzdHJhdGVnaWVzIChydWxlcyldKC4uLy4uL3N0cmF0ZWd5LykgZm9yIHdoaWNoIHJ1bnMgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdCB3b3JrIHdpdGggd2hlbiB0aGV5IGxvZyBpbiB0byB5b3VyIHByb2plY3QuXG4qXG4qIFRoZXJlIGFyZSBtYW55IHdheXMgdG8gY3JlYXRlIG5ldyBydW5zLCBpbmNsdWRpbmcgdGhlIEVwaWNlbnRlci5qcyBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLCB0aGUgUkVTRlRmdWwgW1J1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaSkgYW5kIHRoZSBbTW9kZWwgUnVuIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL290aGVyX2FwaXMvbW9kZWxfYXBpcy9ydW4vKS4gSG93ZXZlciwgZm9yIHNvbWUgcHJvamVjdHMgaXQgbWFrZXMgbW9yZSBzZW5zZSB0byBwaWNrIHVwIHdoZXJlIHRoZSB1c2VyIGxlZnQgb2ZmLCB1c2luZyBhbiBleGlzdGluZyBydW4uIEFuZCBpbiBzb21lIHByb2plY3RzLCB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZSBpcyBjb25kaXRpb25hbCwgZm9yIGV4YW1wbGUgYmFzZWQgb24gY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBleGlzdGluZyBydW4gb3IgeW91ciBvd24ga25vd2xlZGdlIGFib3V0IHRoZSBtb2RlbC4gVGhlIFJ1biBNYW5hZ2VyIHByb3ZpZGVzIHRoaXMgbGV2ZWwgb2YgY29udHJvbDogeW91ciBjYWxsIHRvIGBnZXRSdW4oKWAsIHJhdGhlciB0aGFuIGFsd2F5cyByZXR1cm5pbmcgYSBuZXcgcnVuLCByZXR1cm5zIGEgcnVuIGJhc2VkIG9uIHRoZSBzdHJhdGVneSB5b3UndmUgc3BlY2lmaWVkLiAoTm90ZSB0aGF0IG1hbnkgb2YgdGhlIEVwaWNlbnRlciBzYW1wbGUgcHJvamVjdHMgdXNlIGEgUnVuIFNlcnZpY2UgZGlyZWN0bHksIGJlY2F1c2UgZ2VuZXJhbGx5IHRoZSBzYW1wbGUgcHJvamVjdHMgYXJlIHBsYXllZCBpbiBvbmUgZW5kIHVzZXIgc2Vzc2lvbiBhbmQgZG9uJ3QgY2FyZSBhYm91dCBydW4gc3RhdGVzIG9yIHJ1biBzdHJhdGVnaWVzLilcbipcbipcbiogIyMjIFVzaW5nIHRoZSBSdW4gTWFuYWdlciB0byBjcmVhdGUgYW5kIGFjY2VzcyBydW5zXG4qXG4qIFRvIHVzZSB0aGUgUnVuIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0IGJ5IHBhc3NpbmcgaW46XG4qXG4qICAgKiBgcnVuYDogKHJlcXVpcmVkKSBSdW4gb2JqZWN0LiBNdXN0IGNvbnRhaW46XG4qICAgICAgICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4qICAgICAgICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiogICAgICAgKiBgbW9kZWxgOiBUaGUgbmFtZSBvZiB5b3VyIHByaW1hcnkgbW9kZWwgZmlsZS4gKFNlZSBtb3JlIG9uIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pLilcbiogICAgICAgKiBgc2NvcGVgOiAob3B0aW9uYWwpIFNjb3BlIG9iamVjdCBmb3IgdGhlIHJ1biwgZm9yIGV4YW1wbGUgYHNjb3BlLmdyb3VwYCB3aXRoIHZhbHVlIG9mIHRoZSBuYW1lIG9mIHRoZSBncm91cC5cbiogICAgICAgKiBgc2VydmVyYDogKG9wdGlvbmFsKSBBbiBvYmplY3Qgd2l0aCBvbmUgZmllbGQsIGBob3N0YC4gVGhlIHZhbHVlIG9mIGBob3N0YCBpcyB0aGUgc3RyaW5nIGBhcGkuZm9yaW8uY29tYCwgdGhlIFVSSSBvZiB0aGUgRm9yaW8gc2VydmVyLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0LCBidXQgeW91IGNhbiBwYXNzIGl0IGV4cGxpY2l0bHkgaWYgZGVzaXJlZC4gSXQgaXMgbW9zdCBjb21tb25seSB1c2VkIGZvciBjbGFyaXR5IHdoZW4geW91IGFyZSBbaG9zdGluZyBhbiBFcGljZW50ZXIgcHJvamVjdCBvbiB5b3VyIG93biBzZXJ2ZXJdKC4uLy4uLy4uL2hvd190by9zZWxmX2hvc3RpbmcvKS5cbiogICAgICAgKiBgZmlsZXNgOiAob3B0aW9uYWwpIElmIGFuZCBvbmx5IGlmIHlvdSBhcmUgdXNpbmcgYSBWZW5zaW0gbW9kZWwgYW5kIHlvdSBoYXZlIGFkZGl0aW9uYWwgZGF0YSB0byBwYXNzIGluIHRvIHlvdXIgbW9kZWwsIHlvdSBjYW4gcGFzcyBhIGBmaWxlc2Agb2JqZWN0IHdpdGggdGhlIG5hbWVzIG9mIHRoZSBmaWxlcywgZm9yIGV4YW1wbGU6IGBcImZpbGVzXCI6IHtcImRhdGFcIjogXCJteUV4dHJhRGF0YS54bHNcIn1gLiAoTm90ZSB0aGF0IHlvdSdsbCBhbHNvIG5lZWQgdG8gYWRkIHRoaXMgc2FtZSBmaWxlcyBvYmplY3QgdG8geW91ciBWZW5zaW0gW2NvbmZpZ3VyYXRpb24gZmlsZV0oLi4vLi4vLi4vbW9kZWxfY29kZS92ZW5zaW0vKS4pIFNlZSB0aGUgW3VuZGVybHlpbmcgTW9kZWwgUnVuIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL290aGVyX2FwaXMvbW9kZWxfYXBpcy9ydW4vI3Bvc3QtY3JlYXRpbmctYS1uZXctcnVuLWZvci10aGlzLXByb2plY3QpIGZvciBhZGRpdGlvbmFsIGluZm9ybWF0aW9uLlxuKlxuKiAgICogYHN0cmF0ZWd5YDogKG9wdGlvbmFsKSBSdW4gY3JlYXRpb24gc3RyYXRlZ3kgZm9yIHdoZW4gdG8gY3JlYXRlIGEgbmV3IHJ1biBhbmQgd2hlbiB0byByZXVzZSBhbiBlbmQgdXNlcidzIGV4aXN0aW5nIHJ1bi4gU2VlIFtSdW4gTWFuYWdlciBTdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pIGZvciBkZXRhaWxzLiBEZWZhdWx0cyB0byBgbmV3LWlmLWluaXRpYWxpemVkYC5cbipcbiogICAqIGBzZXNzaW9uS2V5YDogKG9wdGlvbmFsKSBOYW1lIG9mIGJyb3dzZXIgY29va2llIGluIHdoaWNoIHRvIHN0b3JlIHJ1biBpbmZvcm1hdGlvbiwgaW5jbHVkaW5nIHJ1biBpZC4gTWFueSBjb25kaXRpb25hbCBzdHJhdGVnaWVzLCBpbmNsdWRpbmcgdGhlIHByb3ZpZGVkIHN0cmF0ZWdpZXMsIHJlbHkgb24gdGhpcyBicm93c2VyIGNvb2tpZSB0byBzdG9yZSB0aGUgcnVuIGlkIGFuZCBoZWxwIG1ha2UgdGhlIGRlY2lzaW9uIG9mIHdoZXRoZXIgdG8gY3JlYXRlIGEgbmV3IHJ1biBvciB1c2UgYW4gZXhpc3Rpbmcgb25lLiBUaGUgbmFtZSBvZiB0aGlzIGNvb2tpZSBkZWZhdWx0cyB0byBgZXBpY2VudGVyLXNjZW5hcmlvYCBhbmQgY2FuIGJlIHNldCB3aXRoIHRoZSBgc2Vzc2lvbktleWAgcGFyYW1ldGVyLlxuKlxuKlxuKiBBZnRlciBpbnN0YW50aWF0aW5nIGEgUnVuIE1hbmFnZXIsIG1ha2UgYSBjYWxsIHRvIGBnZXRSdW4oKWAgd2hlbmV2ZXIgeW91IG5lZWQgdG8gYWNjZXNzIGEgcnVuIGZvciB0aGlzIGVuZCB1c2VyLiBUaGUgYFJ1bk1hbmFnZXIucnVuYCBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFtSdW4gU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykuIFRoZSBSdW4gU2VydmljZSBhbGxvd3MgeW91IHRvIGFjY2VzcyB2YXJpYWJsZXMsIGNhbGwgb3BlcmF0aW9ucywgZXRjLlxuKlxuKiAqKkV4YW1wbGUqKlxuKlxuKiAgICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuKiAgICAgICAgICAgcnVuOiB7XG4qICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgICAgICAgbW9kZWw6ICdzdXBwbHktY2hhaW4tbW9kZWwuamwnLFxuKiAgICAgICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuKiAgICAgICAgICAgfSxcbiogICAgICAgICAgIHN0cmF0ZWd5OiAnYWx3YXlzLW5ldycsXG4qICAgICAgICAgICBzZXNzaW9uS2V5OiAnZXBpY2VudGVyLXNlc3Npb24nXG4qICAgICAgIH0pO1xuKiAgICAgICBybS5nZXRSdW4oKVxuKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuKSB7XG4qICAgICAgICAgICAgICAgLy8gdGhlIHJldHVybiB2YWx1ZSBvZiBnZXRSdW4oKSBpcyBhIHJ1biBvYmplY3RcbiogICAgICAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuKiAgICAgICAgICAgICAgIC8vIHRoZSBSdW5NYW5hZ2VyLnJ1biBhbHNvIGNvbnRhaW5zIHRoZSBpbnN0YW50aWF0ZWQgUnVuIFNlcnZpY2UsXG4qICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4qICAgICAgICAgICAgICAgcm0ucnVuLmRvKCdydW5Nb2RlbCcpO1xuKiAgICAgICB9KVxuKlxuKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHN0cmF0ZWdpZXNNYXAgPSByZXF1aXJlKCcuL3J1bi1zdHJhdGVnaWVzL3N0cmF0ZWdpZXMtbWFwJyk7XG52YXIgc3BlY2lhbE9wZXJhdGlvbnMgPSByZXF1aXJlKCcuL3NwZWNpYWwtb3BlcmF0aW9ucycpO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG5cbmZ1bmN0aW9uIHBhdGNoUnVuU2VydmljZShzZXJ2aWNlLCBtYW5hZ2VyKSB7XG4gICAgaWYgKHNlcnZpY2UucGF0Y2hlZCkge1xuICAgICAgICByZXR1cm4gc2VydmljZTtcbiAgICB9XG5cbiAgICB2YXIgb3JpZyA9IHNlcnZpY2UuZG87XG4gICAgc2VydmljZS5kbyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YXIgcmVzZXJ2ZWRPcHMgPSBPYmplY3Qua2V5cyhzcGVjaWFsT3BlcmF0aW9ucyk7XG4gICAgICAgIGlmIChyZXNlcnZlZE9wcy5pbmRleE9mKG9wZXJhdGlvbikgPT09IC0xKSB7XG4gICAgICAgICAgICByZXR1cm4gb3JpZy5hcHBseShzZXJ2aWNlLCBhcmd1bWVudHMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHNwZWNpYWxPcGVyYXRpb25zW29wZXJhdGlvbl0uY2FsbChzZXJ2aWNlLCBwYXJhbXMsIG9wdGlvbnMsIG1hbmFnZXIpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHNlcnZpY2UucGF0Y2hlZCA9IHRydWU7XG5cbiAgICByZXR1cm4gc2VydmljZTtcbn1cblxuXG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBSdW4gY3JlYXRpb24gc3RyYXRlZ3kgZm9yIHdoZW4gdG8gY3JlYXRlIGEgbmV3IHJ1biBhbmQgd2hlbiB0byByZXVzZSBhbiBlbmQgdXNlcidzIGV4aXN0aW5nIHJ1bi4gU2VlIFtSdW4gTWFuYWdlciBTdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pIGZvciBkZXRhaWxzLiBEZWZhdWx0cyB0byBgbmV3LWlmLWluaXRpYWxpemVkYC5cbiAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAqL1xuXG4gICAgc3RyYXRlZ3k6ICduZXctaWYtaW5pdGlhbGl6ZWQnXG59O1xuXG5mdW5jdGlvbiBSdW5NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5ydW4gaW5zdGFuY2VvZiBSdW5TZXJ2aWNlKSB7XG4gICAgICAgIHRoaXMucnVuID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnJ1biA9IG5ldyBSdW5TZXJ2aWNlKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH1cblxuICAgIHBhdGNoUnVuU2VydmljZSh0aGlzLnJ1biwgdGhpcyk7XG5cbiAgICB2YXIgU3RyYXRlZ3lDdG9yID0gdHlwZW9mIHRoaXMub3B0aW9ucy5zdHJhdGVneSA9PT0gJ2Z1bmN0aW9uJyA/IHRoaXMub3B0aW9ucy5zdHJhdGVneSA6IHN0cmF0ZWdpZXNNYXBbdGhpcy5vcHRpb25zLnN0cmF0ZWd5XTtcblxuICAgIGlmICghU3RyYXRlZ3lDdG9yKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignU3BlY2lmaWVkIHJ1biBjcmVhdGlvbiBzdHJhdGVneSB3YXMgaW52YWxpZDonLCB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kpO1xuICAgIH1cblxuICAgIHRoaXMuc3RyYXRlZ3kgPSBuZXcgU3RyYXRlZ3lDdG9yKHRoaXMucnVuLCB0aGlzLm9wdGlvbnMpO1xufVxuXG5SdW5NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBydW4gb2JqZWN0IGZvciBhICdnb29kJyBydW4uXG4gICAgICpcbiAgICAgKiBBIGdvb2QgcnVuIGlzIGRlZmluZWQgYnkgdGhlIHN0cmF0ZWd5LiBGb3IgZXhhbXBsZSwgaWYgdGhlIHN0cmF0ZWd5IGlzIGBhbHdheXMtbmV3YCwgdGhlIGNhbGxcbiAgICAgKiB0byBgZ2V0UnVuKClgIGFsd2F5cyByZXR1cm5zIGEgbmV3bHkgY3JlYXRlZCBydW47IGlmIHRoZSBzdHJhdGVneSBpcyBgbmV3LWlmLXBlcnNpc3RlZGAsXG4gICAgICogYGdldFJ1bigpYCBjcmVhdGVzIGEgbmV3IHJ1biBpZiB0aGUgcHJldmlvdXMgcnVuIGlzIGluIGEgcGVyc2lzdGVkIHN0YXRlLCBvdGhlcndpc2VcbiAgICAgKiBpdCByZXR1cm5zIHRoZSBwcmV2aW91cyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgbW9yZSBvbiBzdHJhdGVnaWVzLlxuICAgICAqXG4gICAgICogICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHJtLmdldFJ1bigpLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAqICAgICAgICAgIC8vIHVzZSB0aGUgcnVuIG9iamVjdFxuICAgICAqICAgICAgICAgIHZhciB0aGlzUnVuSWQgPSBydW4uaWQ7XG4gICAgICpcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIFJ1biBTZXJ2aWNlIG9iamVjdFxuICAgICAqICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogQHJldHVybiB7JHByb21pc2V9IFByb21pc2UgdG8gY29tcGxldGUgdGhlIGNhbGwuXG4gICAgICovXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5XG4gICAgICAgICAgICAgICAgLmdldFJ1bigpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBydW4gb2JqZWN0IGZvciBhIG5ldyBydW4sIHJlZ2FyZGxlc3Mgb2Ygc3RyYXRlZ3k6IGZvcmNlIGNyZWF0aW9uIG9mIGEgbmV3IHJ1bi5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5yZXNldCgpLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAqICAgICAgICAgIC8vIHVzZSB0aGUgKG5ldykgcnVuIG9iamVjdFxuICAgICAqICAgICAgICAgIHZhciB0aGlzUnVuSWQgPSBydW4uaWQ7XG4gICAgICpcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIFJ1biBTZXJ2aWNlIG9iamVjdFxuICAgICAqICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gYHJ1blNlcnZpY2VPcHRpb25zYCBUaGUgb3B0aW9ucyBvYmplY3QgdG8gY29uZmlndXJlIHRoZSBSdW4gU2VydmljZS4gU2VlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pIGZvciBtb3JlLlxuICAgICAqL1xuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RyYXRlZ3kucmVzZXQocnVuU2VydmljZU9wdGlvbnMpO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUnVuTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gYWx3YXlzIGNyZWF0ZSBhIG5ldyBydW4hXG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgbWFrZVNlcSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvbWFrZS1zZXF1ZW5jZScpO1xudmFyIEJhc2UgPSByZXF1aXJlKCcuL2lkZW50aXR5LXN0cmF0ZWd5Jyk7XG52YXIgU2Vzc2lvblN0b3JlID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIFVybFNlcnZpY2UgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBzZXNzaW9uU3RvcmUgPSBuZXcgU2Vzc2lvblN0b3JlKHt9KTtcbnZhciB1cmxTZXJ2aWNlID0gbmV3IFVybFNlcnZpY2UoKTtcbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc2Vzc2lvbktleToga2V5TmFtZXMuU1RSQVRFR1lfU0VTU0lPTl9LRVksXG4gICAgcGF0aDogJydcbn07XG5cbmZ1bmN0aW9uIHNldFJ1bkluU2Vzc2lvbihzZXNzaW9uS2V5LCBydW4sIHBhdGgpIHtcbiAgICBpZiAoIXBhdGgpIHtcbiAgICAgICAgaWYgKCF1cmxTZXJ2aWNlLmlzTG9jYWxob3N0KCkpIHtcbiAgICAgICAgICAgIHBhdGggPSAnLycgKyBbdXJsU2VydmljZS5hcHBQYXRoLCB1cmxTZXJ2aWNlLmFjY291bnRQYXRoLCB1cmxTZXJ2aWNlLnByb2plY3RQYXRoXS5qb2luKCcvJyk7XG4gICAgICAgICAgICAvLyBtYWtlIHN1cmUgd2UgZG9uJ3QgZ2V0IGNvbnNlY3V0ZWl2ZSAnLycgc28gd2UgaGF2ZSBhIHZhbGlkIHBhdGggZm9yIHRoZSBzZXNzaW9uXG4gICAgICAgICAgICBwYXRoID0gcGF0aC5yZXBsYWNlKC9cXC97Mix9L2csJy8nKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHBhdGggPSAnJztcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBzZXQgdGhlIHNlZXNpb25LZXkgZm9yIHRoZSBydW5cbiAgICBzZXNzaW9uU3RvcmUuc2V0KHNlc3Npb25LZXksIEpTT04uc3RyaW5naWZ5KHsgcnVuSWQ6IHJ1bi5pZCB9KSwgeyByb290OiBwYXRoIH0pO1xufVxuXG4vKipcbiogQ29uZGl0aW9uYWwgQ3JlYXRpb24gU3RyYXRlZ3lcbiogVGhpcyBzdHJhdGVneSB3aWxsIHRyeSB0byBnZXQgdGhlIHJ1biBzdG9yZWQgaW4gdGhlIGNvb2tpZSBhbmRcbiogZXZhbHVhdGUgaWYgbmVlZHMgdG8gY3JlYXRlIGEgbmV3IHJ1biBieSBjYWxsaW5nIHRoZSAnY29uZGl0aW9uJyBmdW5jdGlvblxuKi9cblxuLyoganNoaW50IGVxbnVsbDogdHJ1ZSAqL1xudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gU3RyYXRlZ3kocnVuU2VydmljZSwgY29uZGl0aW9uLCBvcHRpb25zKSB7XG5cbiAgICAgICAgaWYgKGNvbmRpdGlvbiA9PSBudWxsKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvbmRpdGlvbmFsIHN0cmF0ZWd5IG5lZWRzIGEgY29uZGl0aW9uIHRvIGNyZWF0ZXRlIGEgcnVuJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMucnVuID0gbWFrZVNlcShydW5TZXJ2aWNlKTtcbiAgICAgICAgdGhpcy5jb25kaXRpb24gPSB0eXBlb2YgY29uZGl0aW9uICE9PSAnZnVuY3Rpb24nID8gZnVuY3Rpb24gKCkgeyByZXR1cm4gY29uZGl0aW9uOyB9IDogY29uZGl0aW9uO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnJ1bk9wdGlvbnMgPSB0aGlzLm9wdGlvbnMucnVuO1xuICAgIH0sXG5cbiAgICBydW5PcHRpb25zV2l0aFNjb3BlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1c2VyU2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICByZXR1cm4gJC5leHRlbmQoe1xuICAgICAgICAgICAgc2NvcGU6IHsgZ3JvdXA6IHVzZXJTZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIG9wdCA9IHRoaXMucnVuT3B0aW9uc1dpdGhTY29wZSgpO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1blxuICAgICAgICAgICAgICAgIC5jcmVhdGUob3B0LCBydW5TZXJ2aWNlT3B0aW9ucylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oX3RoaXMub3B0aW9ucy5zZXNzaW9uS2V5LCBydW4sIF90aGlzLm9wdGlvbnMucGF0aCk7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5zdGFydCgpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJ1blNlc3Npb24gPSBKU09OLnBhcnNlKHNlc3Npb25TdG9yZS5nZXQodGhpcy5vcHRpb25zLnNlc3Npb25LZXkpKTtcblxuICAgICAgICBpZiAocnVuU2Vzc2lvbiAmJiBydW5TZXNzaW9uLnJ1bklkKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fbG9hZEFuZENoZWNrKHJ1blNlc3Npb24pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVzZXQoKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVuU2Vzc2lvbikge1xuICAgICAgICB2YXIgc2hvdWxkQ3JlYXRlID0gZmFsc2U7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAubG9hZChydW5TZXNzaW9uLnJ1bklkLCBudWxsLCB7XG4gICAgICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIHNob3VsZENyZWF0ZSA9IF90aGlzLmNvbmRpdGlvbi5jYWxsKF90aGlzLCBydW4sIGhlYWRlcnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNob3VsZENyZWF0ZSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgb3B0ID0gX3RoaXMucnVuT3B0aW9uc1dpdGhTY29wZSgpO1xuICAgICAgICAgICAgICAgICAgICAvLyB3ZSBuZWVkIHRvIGRvIHRoaXMsIG9uIHRoZSBvcmlnaW5hbCBydW5TZXJ2aWNlIChpZSBub3Qgc2VxdWVuY2lhbGl6ZWQpXG4gICAgICAgICAgICAgICAgICAgIC8vIHNvIHdlIGRvbid0IGdldCBpbiB0aGUgbWlkZGxlIG9mIHRoZSBxdWV1ZVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gX3RoaXMucnVuLm9yaWdpbmFsLmNyZWF0ZShvcHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFJ1bkluU2Vzc2lvbihfdGhpcy5vcHRpb25zLnNlc3Npb25LZXksIHJ1bik7XG4gICAgICAgICAgICAgICAgICAgICAgICBydW4uZnJlc2hseUNyZWF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIEJhc2UgPSB7fTtcblxuLy8gSW50ZXJmYWNlIHRoYXQgYWxsIHN0cmF0ZWdpZXMgbmVlZCB0byBpbXBsZW1lbnRcbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlICA9IHJ1blNlcnZpY2U7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIHJldHVybiBhIG5ld2x5IGNyZWF0ZWQgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSgpLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIHJldHVybiBhIHVzYWJsZSBydW5cbiAgICAgICAgcmV0dXJuICQuRGVmZXJyZWQoKS5yZXNvbHZlKHRoaXMucnVuU2VydmljZSkucHJvbWlzZSgpO1xuICAgIH1cbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG5cbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFdvcmxkQXBpQWRhcHRlciA9IHJlcXVpcmUoJy4uLy4uL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuXG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSA9IHJ1blNlcnZpY2U7XG4gICAgICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgICAgIHRoaXMuX2F1dGggPSBuZXcgQXV0aE1hbmFnZXIoKTtcbiAgICAgICAgdGhpcy5fbG9hZFJ1biA9IHRoaXMuX2xvYWRSdW4uYmluZCh0aGlzKTtcbiAgICAgICAgdGhpcy53b3JsZEFwaSA9IG5ldyBXb3JsZEFwaUFkYXB0ZXIodGhpcy5vcHRpb25zLnJ1bik7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgdmFyIGN1ckdyb3VwTmFtZSA9IHNlc3Npb24uZ3JvdXBOYW1lO1xuXG4gICAgICAgIHJldHVybiB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLndvcmxkQXBpLm5ld1J1bkZvcldvcmxkKHdvcmxkLmlkKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgdmFyIHdvcmxkQXBpID0gdGhpcy53b3JsZEFwaTtcbiAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLm1vZGVsO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuXG4gICAgICAgIGlmICghY3VyVXNlcklkKSB7XG4gICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCh7IHN0YXR1c0NvZGU6IDQwMCwgZXJyb3I6ICdXZSBuZWVkIGFuIGF1dGhlbnRpY2F0ZWQgdXNlciB0byBqb2luIGEgbXVsdGlwbGF5ZXIgd29ybGQuIChFUlI6IG5vIHVzZXJJZCBpbiBzZXNzaW9uKScgfSwgc2Vzc2lvbikucHJvbWlzZSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGxvYWRSdW5Gcm9tV29ybGQgPSBmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCh7IHN0YXR1c0NvZGU6IDQwNCwgZXJyb3I6ICdUaGUgdXNlciBpcyBub3QgaW4gYW55IHdvcmxkLicgfSwgeyBvcHRpb25zOiB0aGlzLm9wdGlvbnMsIHNlc3Npb246IHNlc3Npb24gfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50UnVuSWQoeyBtb2RlbDogbW9kZWwsIGZpbHRlcjogd29ybGQuaWQgfSlcbiAgICAgICAgICAgICAgICAudGhlbihfdGhpcy5fbG9hZFJ1bilcbiAgICAgICAgICAgICAgICAudGhlbihkdGQucmVzb2x2ZSlcbiAgICAgICAgICAgICAgICAuZmFpbChkdGQucmVqZWN0KTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgc2VydmVyRXJyb3IgPSBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgIC8vIGlzIHRoaXMgcG9zc2libGU/XG4gICAgICAgICAgICBkdGQucmVqZWN0KGVycm9yLCBzZXNzaW9uLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMud29ybGRBcGlcbiAgICAgICAgICAgIC5nZXRDdXJyZW50V29ybGRGb3JVc2VyKGN1clVzZXJJZCwgY3VyR3JvdXBOYW1lKVxuICAgICAgICAgICAgLnRoZW4obG9hZFJ1bkZyb21Xb3JsZClcbiAgICAgICAgICAgIC5mYWlsKHNlcnZlckVycm9yKTtcblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW5TZXJ2aWNlLmxvYWQoaWQsIG51bGwsIG9wdGlvbnMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCcgfHwgcnVuLmluaXRpYWxpemVkO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgQ29uZGl0aW9uYWxTdHJhdGVneSA9IHJlcXVpcmUoJy4vY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3knKTtcblxudmFyIF9fc3VwZXIgPSBDb25kaXRpb25hbFN0cmF0ZWd5LnByb3RvdHlwZTtcblxuLypcbiogIGNyZWF0ZSBhIG5ldyBydW4gb25seSBpZiBub3RoaW5nIGlzIHN0b3JlZCBpbiB0aGUgY29va2llXG4qICB0aGlzIGlzIHVzZWZ1bCBmb3IgYmFzZVJ1bnMuXG4qL1xudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKENvbmRpdGlvbmFsU3RyYXRlZ3ksIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgX19zdXBlci5jb25zdHJ1Y3Rvci5jYWxsKHRoaXMsIHJ1blNlcnZpY2UsIHRoaXMuY3JlYXRlSWYsIG9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICBjcmVhdGVJZjogZnVuY3Rpb24gKHJ1biwgaGVhZGVycykge1xuICAgICAgICAvLyBpZiB3ZSBhcmUgaGVyZSwgaXQgbWVhbnMgdGhhdCB0aGUgcnVuIGV4aXN0cy4uLiBzbyB3ZSBkb24ndCBuZWVkIGEgbmV3IG9uZVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgQ29uZGl0aW9uYWxTdHJhdGVneSA9IHJlcXVpcmUoJy4vY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3knKTtcblxudmFyIF9fc3VwZXIgPSBDb25kaXRpb25hbFN0cmF0ZWd5LnByb3RvdHlwZTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKENvbmRpdGlvbmFsU3RyYXRlZ3ksIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgX19zdXBlci5jb25zdHJ1Y3Rvci5jYWxsKHRoaXMsIHJ1blNlcnZpY2UsIHRoaXMuY3JlYXRlSWYsIG9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICBjcmVhdGVJZjogZnVuY3Rpb24gKHJ1biwgaGVhZGVycykge1xuICAgICAgICByZXR1cm4gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIElkZW50aXR5U3RyYXRlZ3kgPSByZXF1aXJlKCcuL2lkZW50aXR5LXN0cmF0ZWd5Jyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi8uLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgU3RhdGVBcGkgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGtleU5hbWVzID0gcmVxdWlyZSgnLi4va2V5LW5hbWVzJyk7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICBzdG9yZToge1xuICAgICAgICBzeW5jaHJvbm91czogdHJ1ZVxuICAgIH1cbn07XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShJZGVudGl0eVN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW4gPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnJ1bk9wdGlvbnMgPSB0aGlzLm9wdGlvbnMucnVuO1xuICAgICAgICB0aGlzLl9zdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh0aGlzLm9wdGlvbnMuc3RvcmUpO1xuICAgICAgICB0aGlzLnN0YXRlQXBpID0gbmV3IFN0YXRlQXBpKCk7XG4gICAgICAgIHRoaXMuX2F1dGggPSBuZXcgQXV0aE1hbmFnZXIoKTtcblxuICAgICAgICB0aGlzLl9sb2FkQW5kQ2hlY2sgPSB0aGlzLl9sb2FkQW5kQ2hlY2suYmluZCh0aGlzKTtcbiAgICAgICAgdGhpcy5fcmVzdG9yZVJ1biA9IHRoaXMuX3Jlc3RvcmVSdW4uYmluZCh0aGlzKTtcbiAgICAgICAgdGhpcy5fZ2V0QWxsUnVucyA9IHRoaXMuX2dldEFsbFJ1bnMuYmluZCh0aGlzKTtcbiAgICAgICAgdGhpcy5fbG9hZFJ1biA9IHRoaXMuX2xvYWRSdW4uYmluZCh0aGlzKTtcbiAgICB9LFxuXG4gICAgcmVzZXQ6IGZ1bmN0aW9uIChydW5TZXJ2aWNlT3B0aW9ucykge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQoe1xuICAgICAgICAgICAgc2NvcGU6IHsgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lIH1cbiAgICAgICAgfSwgdGhpcy5ydW5PcHRpb25zKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5ydW5cbiAgICAgICAgICAgIC5jcmVhdGUob3B0LCBydW5TZXJ2aWNlT3B0aW9ucylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICBydW4uZnJlc2hseUNyZWF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRBbGxSdW5zKClcbiAgICAgICAgICAgIC50aGVuKHRoaXMuX2xvYWRBbmRDaGVjayk7XG4gICAgfSxcblxuICAgIF9nZXRBbGxSdW5zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZSh0aGlzLl9zdG9yZS5nZXQoa2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZKSB8fCAne30nKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuLnF1ZXJ5KHtcbiAgICAgICAgICAgICd1c2VyLmlkJzogc2Vzc2lvbi51c2VySWQgfHwgJzAwMDAnLFxuICAgICAgICAgICAgJ3Njb3BlLmdyb3VwJzogc2Vzc2lvbi5ncm91cE5hbWVcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9sb2FkQW5kQ2hlY2s6IGZ1bmN0aW9uIChydW5zKSB7XG4gICAgICAgIGlmICghcnVucyB8fCAhcnVucy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZGF0ZUNvbXAgPSBmdW5jdGlvbiAoYSwgYikgeyByZXR1cm4gbmV3IERhdGUoYi5kYXRlKSAtIG5ldyBEYXRlKGEuZGF0ZSk7IH07XG4gICAgICAgIHZhciBsYXRlc3RSdW4gPSBydW5zLnNvcnQoZGF0ZUNvbXApWzBdO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgc2hvdWxkUmVwbGF5ID0gZmFsc2U7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuLmxvYWQobGF0ZXN0UnVuLmlkLCBudWxsLCB7XG4gICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAocnVuLCBtc2csIGhlYWRlcnMpIHtcbiAgICAgICAgICAgICAgICBzaG91bGRSZXBsYXkgPSBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgIHJldHVybiBzaG91bGRSZXBsYXkgPyBfdGhpcy5fcmVzdG9yZVJ1bihydW4uaWQpIDogcnVuO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX3Jlc3RvcmVSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZUFwaS5yZXBsYXkoeyBydW5JZDogcnVuSWQgfSlcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXNwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLl9sb2FkUnVuKHJlc3AucnVuKTtcbiAgICAgICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZFJ1bjogZnVuY3Rpb24gKGlkLCBvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwibW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgJ25ldy1pZi1pbml0aWFsaXplZCc6IHJlcXVpcmUoJy4vbmV3LWlmLWluaXRpYWxpemVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1wZXJzaXN0ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3knKSxcbiAgICAnbmV3LWlmLW1pc3NpbmcnOiByZXF1aXJlKCcuL25ldy1pZi1taXNzaW5nLXN0cmF0ZWd5JyksXG4gICAgJ2Fsd2F5cy1uZXcnOiByZXF1aXJlKCcuL2Fsd2F5cy1uZXctc3RyYXRlZ3knKSxcbiAgICAnbXVsdGlwbGF5ZXInOiByZXF1aXJlKCcuL211bHRpcGxheWVyLXN0cmF0ZWd5JyksXG4gICAgJ3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllcic6IHJlcXVpcmUoJy4vcGVyc2lzdGVudC1zaW5nbGUtcGxheWVyLXN0cmF0ZWd5JyksXG4gICAgJ25vbmUnOiByZXF1aXJlKCcuL2lkZW50aXR5LXN0cmF0ZWd5Jylcbn07XG4iLCIndXNlIHN0cmljdCc7XG52YXIgUnVuU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICB2YWxpZEZpbHRlcjogeyBzYXZlZDogdHJ1ZSB9XG59O1xuXG5mdW5jdGlvbiBTY2VuYXJpb01hbmFnZXIob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgdGhpcy5ydW5TZXJ2aWNlID0gdGhpcy5vcHRpb25zLnJ1biB8fCBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMpO1xufVxuXG5TY2VuYXJpb01hbmFnZXIucHJvdG90eXBlID0ge1xuICAgIGdldFJ1bnM6IGZ1bmN0aW9uIChmaWx0ZXIpIHtcbiAgICAgICAgdGhpcy5maWx0ZXIgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5vcHRpb25zLnZhbGlkRmlsdGVyLCBmaWx0ZXIpO1xuICAgICAgICByZXR1cm4gdGhpcy5ydW5TZXJ2aWNlLnF1ZXJ5KHRoaXMuZmlsdGVyKTtcbiAgICB9LFxuXG4gICAgbG9hZFZhcmlhYmxlczogZnVuY3Rpb24gKHZhcnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlciwgeyBpbmNsdWRlOiB2YXJzIH0pO1xuICAgIH0sXG5cbiAgICBzYXZlOiBmdW5jdGlvbiAocnVuLCBtZXRhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSgkLmV4dGVuZCh0cnVlLCB7fSwgeyBzYXZlZDogdHJ1ZSB9LCBtZXRhKSk7XG4gICAgfSxcblxuICAgIGFyY2hpdmU6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2dldFNlcnZpY2UocnVuKS5zYXZlKHsgc2F2ZWQ6IGZhbHNlIH0pO1xuICAgIH0sXG5cbiAgICBfZ2V0U2VydmljZTogZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICBpZiAodHlwZW9mIHJ1biA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgUnVuU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgIHRoaXMub3B0aW9ucywgeyBmaWx0ZXI6IHJ1biB9KSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHJ1biA9PT0gJ29iamVjdCcgJiYgcnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignU2F2ZSBtZXRob2QgcmVxdWlyZXMgYSBydW4gc2VydmljZSBvciBhIHJ1bklkJyk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKHJ1bklkKSB7XG4gICAgICAgIHJldHVybiBuZXcgUnVuU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgIHRoaXMub3B0aW9ucywgeyBmaWx0ZXI6IHJ1bklkIH0pKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNjZW5hcmlvTWFuYWdlcjtcblxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHJlc2V0OiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKSB7XG4gICAgICAgIHJldHVybiBtYW5hZ2VyLnJlc2V0KG9wdGlvbnMpO1xuICAgIH1cbn07XG4iLCIvKipcbiogIyMgV29ybGQgTWFuYWdlclxuKlxuKiBBcyBkaXNjdXNzZWQgdW5kZXIgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKSwgYSBbcnVuXSguLi8uLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgZW5kIHVzZXIgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwuIEZvciBidWlsZGluZyBtdWx0aXBsYXllciBzaW11bGF0aW9ucyB5b3UgdHlwaWNhbGx5IHdhbnQgbXVsdGlwbGUgZW5kIHVzZXJzIHRvIHNoYXJlIHRoZSBzYW1lIHNldCBvZiBpbnRlcmFjdGlvbnMsIGFuZCB3b3JrIHdpdGhpbiBhIGNvbW1vbiBzdGF0ZS4gRXBpY2VudGVyIGFsbG93cyB5b3UgdG8gY3JlYXRlIFwid29ybGRzXCIgdG8gaGFuZGxlIHN1Y2ggY2FzZXMuXG4qXG4qIFRoZSBXb3JsZCBNYW5hZ2VyIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIHRyYWNrIGFuZCBhY2Nlc3MgdGhlIGN1cnJlbnQgd29ybGQgYW5kIHJ1biBmb3IgcGFydGljdWxhciBlbmQgdXNlcnMuIEl0IGlzIHR5cGljYWxseSB1c2VkIGluIHBhZ2VzIHRoYXQgZW5kIHVzZXJzIHdpbGwgaW50ZXJhY3Qgd2l0aC4gKFRoZSByZWxhdGVkIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKSBoYW5kbGVzIGNyZWF0aW5nIG11bHRpcGxheWVyIHdvcmxkcywgYW5kIGFkZGluZyBhbmQgcmVtb3ZpbmcgZW5kIHVzZXJzIGFuZCBydW5zIGZyb20gYSB3b3JsZC4gQmVjYXVzZSBvZiB0aGlzLCB0eXBpY2FsbHkgdGhlIFdvcmxkIEFkYXB0ZXIgaXMgdXNlZCBmb3IgZmFjaWxpdGF0b3IgcGFnZXMgaW4geW91ciBwcm9qZWN0LilcbipcbiogIyMjIFVzaW5nIHRoZSBXb3JsZCBNYW5hZ2VyXG4qXG4qIFRvIHVzZSB0aGUgV29ybGQgTWFuYWdlciwgaW5zdGFudGlhdGUgaXQuIFRoZW4sIG1ha2UgY2FsbHMgdG8gYW55IG9mIHRoZSBtZXRob2RzIHlvdSBuZWVkLlxuKlxuKiBXaGVuIHlvdSBpbnN0YW50aWF0ZSBhIFdvcmxkIE1hbmFnZXIsIHRoZSB3b3JsZCdzIGFjY291bnQgaWQsIHByb2plY3QgaWQsIGFuZCBncm91cCBhcmUgYXV0b21hdGljYWxseSB0YWtlbiBmcm9tIHRoZSBzZXNzaW9uICh0aGFua3MgdG8gdGhlIFtBdXRoZW50aWNhdGlvbiBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlKSkuXG4qXG4qIE5vdGUgdGhhdCB0aGUgV29ybGQgTWFuYWdlciBkb2VzICpub3QqIGNyZWF0ZSB3b3JsZHMgYXV0b21hdGljYWxseS4gKFRoaXMgaXMgZGlmZmVyZW50IHRoYW4gdGhlIFtSdW4gTWFuYWdlcl0oLi4vcnVuLW1hbmFnZXIpLikgSG93ZXZlciwgeW91IGNhbiBwYXNzIGluIHNwZWNpZmljIG9wdGlvbnMgdG8gYW55IHJ1bnMgY3JlYXRlZCBieSB0aGUgbWFuYWdlciwgdXNpbmcgYSBgcnVuYCBvYmplY3QuXG4qXG4qIFRoZSBwYXJhbWV0ZXJzIGZvciBjcmVhdGluZyBhIFdvcmxkIE1hbmFnZXIgYXJlOlxuKlxuKiAgICogYGFjY291bnRgOiBUaGUgKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSBmb3IgdGhpcyBwcm9qZWN0LlxuKiAgICogYHByb2plY3RgOiBUaGUgKipQcm9qZWN0IElEKiogZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBncm91cGA6IFRoZSAqKkdyb3VwIE5hbWUqKiBmb3IgdGhpcyB3b3JsZC5cbiogICAqIGBydW5gOiBPcHRpb25zIHRvIHVzZSB3aGVuIGNyZWF0aW5nIG5ldyBydW5zIHdpdGggdGhlIG1hbmFnZXIsIGUuZy4gYHJ1bjogeyBmaWxlczogWydkYXRhLnhscyddIH1gLlxuKiAgICogYHJ1bi5tb2RlbGA6IFRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IG1vZGVsIGZpbGUgZm9yIHRoaXMgcHJvamVjdC4gUmVxdWlyZWQgaWYgeW91IGhhdmUgbm90IGFscmVhZHkgcGFzc2VkIGl0IGluIGFzIHBhcnQgb2YgdGhlIGBvcHRpb25zYCBwYXJhbWV0ZXIgZm9yIGFuIGVuY2xvc2luZyBjYWxsLlxuKlxuKiBGb3IgZXhhbXBsZTpcbipcbiogICAgICAgdmFyIHdNZ3IgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4qICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiogICAgICAgICAgcnVuOiB7IG1vZGVsOiAnc3VwcGx5LWNoYWluLnB5JyB9LFxuKiAgICAgICAgICBncm91cDogJ3RlYW0xJ1xuKiAgICAgICB9KTtcbipcbiogICAgICAgd01nci5nZXRDdXJyZW50UnVuKCk7XG4qL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBXb3JsZEFwaSA9IHJlcXVpcmUoJy4uL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbnZhciBSdW5NYW5hZ2VyID0gIHJlcXVpcmUoJy4vcnVuLW1hbmFnZXInKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG52YXIgd29ybGRBcGk7XG5cbi8vIHZhciBkZWZhdWx0cyA9IHtcbi8vICBhY2NvdW50OiAnJyxcbi8vICBwcm9qZWN0OiAnJyxcbi8vICBncm91cDogJycsXG4vLyAgdHJhbnNwb3J0OiB7XG4vLyAgfVxuLy8gfTtcblxuXG5mdW5jdGlvbiBidWlsZFN0cmF0ZWd5KHdvcmxkSWQsIGR0ZCkge1xuXG4gICAgcmV0dXJuIGZ1bmN0aW9uIEN0b3IocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xuXG4gICAgICAgICQuZXh0ZW5kKHRoaXMsIHtcbiAgICAgICAgICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdub3QgaW1wbGVtZW50ZC4gTmVlZCBhcGkgY2hhbmdlcycpO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgICAgICAgICAvL2dldCBvciBjcmVhdGUhXG4gICAgICAgICAgICAgICAgLy8gTW9kZWwgaXMgcmVxdWlyZWQgaW4gdGhlIG9wdGlvbnNcbiAgICAgICAgICAgICAgICB2YXIgbW9kZWwgPSB0aGlzLm9wdGlvbnMucnVuLm1vZGVsIHx8IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkSWQgfSlcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bklkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gX3RoaXMucnVuU2VydmljZS5sb2FkKHJ1bklkKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUuY2FsbCh0aGlzLCBydW4sIF90aGlzLnJ1blNlcnZpY2UpO1xuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAuZmFpbChkdGQucmVqZWN0KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfTtcbn1cblxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucyB8fCB7IHJ1bjoge30sIHdvcmxkOiB7fSB9O1xuXG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMucnVuKTtcbiAgICAkLmV4dGVuZCh0cnVlLCB0aGlzLm9wdGlvbnMsIHRoaXMub3B0aW9ucy53b3JsZCk7XG5cbiAgICB3b3JsZEFwaSA9IG5ldyBXb3JsZEFwaSh0aGlzLm9wdGlvbnMpO1xuICAgIHRoaXMuX2F1dGggPSBuZXcgQXV0aE1hbmFnZXIoKTtcbiAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgdmFyIGFwaSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHdvcmxkIChvYmplY3QpIGFuZCBhbiBpbnN0YW5jZSBvZiB0aGUgW1dvcmxkIEFQSSBBZGFwdGVyXSguLi93b3JsZC1hcGktYWRhcHRlci8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFdvcmxkKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQsIHdvcmxkQWRhcHRlcikge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd29ybGRBZGFwdGVyLmdldEN1cnJlbnRSdW5JZCgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB1c2VyIHdob3NlIHdvcmxkIGlzIGJlaW5nIGFjY2Vzc2VkLiBEZWZhdWx0cyB0byB0aGUgdXNlciBpbiB0aGUgY3VycmVudCBzZXNzaW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cCB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIGdyb3VwIGZvciB0aGUgdXNlciBpbiB0aGUgY3VycmVudCBzZXNzaW9uLlxuICAgICAgICAqL1xuICAgICAgICBnZXRDdXJyZW50V29ybGQ6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIGlmICghdXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWdyb3VwTmFtZSkge1xuICAgICAgICAgICAgICAgIGdyb3VwTmFtZSA9IHNlc3Npb24uZ3JvdXBOYW1lO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRXb3JsZEZvclVzZXIodXNlcklkLCBncm91cE5hbWUpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHVybnMgdGhlIGN1cnJlbnQgcnVuIChvYmplY3QpIGFuZCBhbiBpbnN0YW5jZSBvZiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgd01nci5nZXRDdXJyZW50UnVuKHttb2RlbDogJ215TW9kZWwucHknfSlcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuLCBydW5TZXJ2aWNlKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhydW4uaWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgcnVuU2VydmljZS5kbygnc3RhcnRHYW1lJyk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYG1vZGVsYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBtb2RlbCBmaWxlLiBSZXF1aXJlZCBpZiBub3QgYWxyZWFkeSBwYXNzZWQgaW4gYXMgYHJ1bi5tb2RlbGAgd2hlbiB0aGUgV29ybGQgTWFuYWdlciBpcyBjcmVhdGVkLlxuICAgICAgICAqL1xuICAgICAgICBnZXRDdXJyZW50UnVuOiBmdW5jdGlvbiAobW9kZWwpIHtcbiAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgdmFyIGN1ckdyb3VwTmFtZSA9IHNlc3Npb24uZ3JvdXBOYW1lO1xuXG4gICAgICAgICAgICBmdW5jdGlvbiBnZXRBbmRSZXN0b3JlTGF0ZXN0UnVuKHdvcmxkKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF3b3JsZCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCh7IGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IHBhcnQgb2YgYW55IHdvcmxkIScgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIGN1cnJlbnRXb3JsZElkID0gd29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgdmFyIHJ1bk9wdHMgPSAkLmV4dGVuZCh0cnVlLCBfdGhpcy5vcHRpb25zLCB7IG1vZGVsOiBtb2RlbCB9KTtcbiAgICAgICAgICAgICAgICB2YXIgc3RyYXRlZ3kgPSBidWlsZFN0cmF0ZWd5KGN1cnJlbnRXb3JsZElkLCBkdGQpO1xuICAgICAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSwge1xuICAgICAgICAgICAgICAgICAgICBzdHJhdGVneTogc3RyYXRlZ3ksXG4gICAgICAgICAgICAgICAgICAgIHJ1bjogcnVuT3B0c1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHZhciBybSA9IG5ldyBSdW5NYW5hZ2VyKG9wdCk7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gcm0uZ2V0UnVuKClcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUocnVuLCBybS5ydW5TZXJ2aWNlLCBybSk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLmdldEN1cnJlbnRXb3JsZChjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgICAgICAudGhlbihnZXRBbmRSZXN0b3JlTGF0ZXN0UnVuKTtcblxuICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgYXBpKTtcbn07XG4iLCIvKipcbiAqICMjRmlsZSBBUEkgU2VydmljZVxuICpcbiAqIFRoaXMgaXMgdXNlZCB0byB1cGxvYWQvZG93bmxvYWQgZmlsZXMgZGlyZWN0bHkgb250byBFcGljZW50ZXIsIGFuYWxvZ291cyB0byB1c2luZyB0aGUgRmlsZSBNYW5hZ2VyIFVJIGluIEVwaWNlbnRlciBkaXJlY3RseSBvciBTRlRQaW5nIGZpbGVzIGluLiBUaGUgQXNzZXQgQVBJIGlzIHR5cGljYWxseSB1c2VkIGZvciBhbGwgcHJvamVjdCB1c2UtY2FzZXMsIGFuZCBpdCdzIHVubGlrZWx5IHRoaXMgRmlsZSBTZXJ2aWNlIHdpbGwgYmUgdXNlZCBkaXJlY3RseSBleGNlcHQgYnkgQWRtaW4gdG9vbHMgKGUuZy4gRmxvdyBJbnNwZWN0b3IpLlxuICpcbiAqIFBhcnRpYWxseSBpbXBsZW1lbnRlZC5cbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgLy8gY29uZmlnIHx8IChjb25maWcgPSBjb25maWdTZXJ2aWNlLmdldCgpKTtcbiAgICB2YXIgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkoeyBzeW5jaHJvbm91czogdHJ1ZSB9KTtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8IHN0b3JlLmdldCgnZXBpY2VudGVyLnRva2VuJykgfHwgJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6ICcnLFxuXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG5cbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJylcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBhIGRpcmVjdG9yeSBsaXN0aW5nLCBvciBjb250ZW50cyBvZiBhIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZmlsZVBhdGhgICAgUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBmb2xkZXJUeXBlYCBPbmUgb2YgTW9kZWx8U3RhdGljfE5vZGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGdldENvbnRlbnRzOiBmdW5jdGlvbiAoZmlsZVBhdGgsIGZvbGRlclR5cGUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBwYXRoID0gZm9sZGVyVHlwZSArICcvJyArIGZpbGVQYXRoO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLCB7XG4gICAgICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZmlsZScpICsgcGF0aFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoJycsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG59O1xuIiwiLyoqXG4gKiAjI0Fzc2V0IEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIEFzc2V0IEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gc3RvcmUgYXNzZXRzIC0tIHJlc291cmNlcyBvciBmaWxlcyBvZiBhbnkga2luZCAtLSB1c2VkIGJ5IGEgcHJvamVjdCB3aXRoIGEgc2NvcGUgdGhhdCBpcyBzcGVjaWZpYyB0byBwcm9qZWN0LCBncm91cCwgb3IgZW5kIHVzZXIuXG4gKlxuICogQXNzZXRzIGFyZSB1c2VkIHdpdGggW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL3Byb2plY3RfYWRtaW4vI3RlYW0pLiBPbmUgY29tbW9uIHVzZSBjYXNlIGlzIGhhdmluZyBlbmQgdXNlcnMgaW4gYSBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpIG9yIGluIGEgW211bHRpcGxheWVyIHdvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpIHVwbG9hZCBkYXRhIC0tIHZpZGVvcyBjcmVhdGVkIGR1cmluZyBnYW1lIHBsYXksIHByb2ZpbGUgcGljdHVyZXMgZm9yIGN1c3RvbWl6aW5nIHRoZWlyIGV4cGVyaWVuY2UsIGV0Yy4gLS0gYXMgcGFydCBvZiBwbGF5aW5nIHRocm91Z2ggdGhlIHByb2plY3QuXG4gKlxuICogUmVzb3VyY2VzIGNyZWF0ZWQgdXNpbmcgdGhlIEFzc2V0IEFkYXB0ZXIgYXJlIHNjb3BlZDpcbiAqXG4gKiAgKiBQcm9qZWN0IGFzc2V0cyBhcmUgd3JpdGFibGUgb25seSBieSBbdGVhbSBtZW1iZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSksIHRoYXQgaXMsIEVwaWNlbnRlciBhdXRob3JzLlxuICogICogR3JvdXAgYXNzZXRzIGFyZSB3cml0YWJsZSBieSBhbnlvbmUgd2l0aCBhY2Nlc3MgdG8gdGhlIHByb2plY3QgdGhhdCBpcyBwYXJ0IG9mIHRoYXQgcGFydGljdWxhciBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLiBUaGlzIGluY2x1ZGVzIGFsbCBbdGVhbSBtZW1iZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSkgKEVwaWNlbnRlciBhdXRob3JzKSBhbmQgYW55IFtlbmQgdXNlcnNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2Vycykgd2hvIGFyZSBtZW1iZXJzIG9mIHRoZSBncm91cCAtLSBib3RoIGZhY2lsaXRhdG9ycyBhbmQgc3RhbmRhcmQgZW5kIHVzZXJzLlxuICogICogVXNlciBhc3NldHMgYXJlIHdyaXRhYmxlIGJ5IHRoZSBzcGVjaWZpYyBlbmQgdXNlciwgYW5kIGJ5IHRoZSBmYWNpbGl0YXRvciBvZiB0aGUgZ3JvdXAuXG4gKiAgKiBBbGwgYXNzZXRzIGFyZSByZWFkYWJsZSBieSBhbnlvbmUgd2l0aCB0aGUgZXhhY3QgVVJJLlxuICpcbiAqIFRvIHVzZSB0aGUgQXNzZXQgQWRhcHRlciwgaW5zdGFudGlhdGUgaXQgYW5kIHRoZW4gYWNjZXNzIHRoZSBtZXRob2RzIHByb3ZpZGVkLiBJbnN0YW50aWF0aW5nIHJlcXVpcmVzIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBpbiB0aGUgRXBpY2VudGVyIHVzZXIgaW50ZXJmYWNlKSBhbmQgcHJvamVjdCBpZCAoKipQcm9qZWN0IElEKiopLiBUaGUgZ3JvdXAgbmFtZSBpcyByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSBncm91cCBzY29wZSwgYW5kIHRoZSBncm91cCBuYW1lIGFuZCB1c2VySWQgYXJlIHJlcXVpcmVkIGZvciBhc3NldHMgd2l0aCBhIHVzZXIgc2NvcGUuIElmIG5vdCBpbmNsdWRlZCwgdGhleSBhcmUgdGFrZW4gZnJvbSB0aGUgbG9nZ2VkIGluIHVzZXIncyBzZXNzaW9uIGluZm9ybWF0aW9uIGlmIG5lZWRlZC5cbiAqXG4gKiBXaGVuIGNyZWF0aW5nIGFuIGFzc2V0LCB5b3UgY2FuIHBhc3MgaW4gdGV4dCAoZW5jb2RlZCBkYXRhKSB0byB0aGUgYGNyZWF0ZSgpYCBjYWxsLiBBbHRlcm5hdGl2ZWx5LCB5b3UgY2FuIG1ha2UgdGhlIGBjcmVhdGUoKWAgY2FsbCBhcyBwYXJ0IG9mIGFuIEhUTUwgZm9ybSBhbmQgcGFzcyBpbiBhIGZpbGUgdXBsb2FkZWQgdmlhIHRoZSBmb3JtLlxuICpcbiAqICAgICAgIC8vIGluc3RhbnRpYXRlIHRoZSBBc3NldCBBZGFwdGVyXG4gKiAgICAgICB2YXIgYWEgPSBuZXcgRi5zZXJ2aWNlLkFzc2V0KHtcbiAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAqICAgICAgICAgIHVzZXJJZDogJzEyMzQ1J1xuICogICAgICAgfSk7XG4gKlxuICogICAgICAgLy8gY3JlYXRlIGEgbmV3IGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICogICAgICAgYWEuY3JlYXRlKCd0ZXN0LnR4dCcsIHtcbiAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSFJsYzNRZ1ptbHNaUzQ9JyxcbiAqICAgICAgICAgICBjb250ZW50VHlwZTogJ3RleHQvcGxhaW4nXG4gKiAgICAgICB9LCB7IHNjb3BlOiAndXNlcicgfSk7XG4gKlxuICogICAgICAgLy8gYWx0ZXJuYXRpdmVseSwgY3JlYXRlIGEgbmV3IGFzc2V0IHVzaW5nIGEgZmlsZSB1cGxvYWRlZCB0aHJvdWdoIGEgZm9ybVxuICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICogICAgICAgLy9cbiAqICAgICAgIC8vIDxmb3JtIGlkPVwidXBsb2FkLWZpbGVcIj5cbiAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAqICAgICAgIC8vICAgPGJ1dHRvbiB0eXBlPVwic3VibWl0XCI+VXBsb2FkIG15RmlsZTwvYnV0dG9uPlxuICogICAgICAgLy8gPC9mb3JtPlxuICogICAgICAgLy9cbiAqICAgICAgICQoJyN1cGxvYWQtZmlsZScpLm9uKCdzdWJtaXQnLCBmdW5jdGlvbiAoZSkge1xuICogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI2ZpbGVuYW1lJykudmFsKCk7XG4gKiAgICAgICAgICB2YXIgZGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gKiAgICAgICAgICBkYXRhLmFwcGVuZCgnZmlsZScsIGlucHV0Q29udHJvbC5maWxlc1swXSwgZmlsZW5hbWUpO1xuICpcbiAqICAgICAgICAgIGFhLmNyZWF0ZShmaWxlbmFtZSwgZGF0YSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICogICAgICAgfSk7XG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xuLy8gdmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9tYW5hZ2Vycy9rZXktbmFtZXMnKTtcblxudmFyIGFwaUVuZHBvaW50ID0gJ2Fzc2V0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG4gICAgdmFyIHNlc3Npb24gPSBKU09OLnBhcnNlKHN0b3JlLmdldChrZXlOYW1lcy5FUElfU0VTU0lPTl9LRVkpIHx8ICd7fScpO1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiBzdG9yZS5nZXQoa2V5TmFtZXMuRVBJX0NPT0tJRV9LRVkpIHx8ICcnLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBncm91cCBuYW1lLiBEZWZhdWx0cyB0byBzZXNzaW9uJ3MgYGdyb3VwTmFtZWAuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBncm91cDogc2Vzc2lvbi5ncm91cE5hbWUsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgdXNlciBpZC4gRGVmYXVsdHMgdG8gc2Vzc2lvbidzIGB1c2VySWRgLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdXNlcklkOiBzZXNzaW9uLnVzZXJJZCxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBzY29wZSBmb3IgdGhlIGFzc2V0LiBWYWxpZCB2YWx1ZXMgYXJlOiBgdXNlcmAsIGBncm91cGAsIGFuZCBgcHJvamVjdGAuIFNlZSBhYm92ZSBmb3IgdGhlIHJlcXVpcmVkIHBlcm1pc3Npb25zIHRvIHdyaXRlIHRvIGVhY2ggc2NvcGUuIERlZmF1bHRzIHRvIGB1c2VyYCwgbWVhbmluZyB0aGUgY3VycmVudCBlbmQgdXNlciBvciBhIGZhY2lsaXRhdG9yIGluIHRoZSBlbmQgdXNlcidzIGdyb3VwIGNhbiBlZGl0IHRoZSBhc3NldC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHNjb3BlOiAndXNlcicsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBEZXRlcm1pbmVzIGlmIGEgcmVxdWVzdCB0byBsaXN0IHRoZSBhc3NldHMgaW4gYSBzY29wZSBpbmNsdWRlcyB0aGUgY29tcGxldGUgVVJMIGZvciBlYWNoIGFzc2V0IChgdHJ1ZWApLCBvciBvbmx5IHRoZSBmaWxlIG5hbWVzIG9mIHRoZSBhc3NldHMgKGBmYWxzZWApLiBEZWZhdWx0cyB0byBgdHJ1ZWAuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgZnVsbFVybDogdHJ1ZSxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSB0cmFuc3BvcnQgb2JqZWN0IGNvbnRhaW5zIHRoZSBvcHRpb25zIHBhc3NlZCB0byB0aGUgWEhSIHJlcXVlc3QuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHtcbiAgICAgICAgICAgIHByb2Nlc3NEYXRhOiBmYWxzZVxuICAgICAgICB9XG4gICAgfTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmFjY291bnQgPSB1cmxDb25maWcuYWNjb3VudFBhdGg7XG4gICAgfVxuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgYXNzZXRBcGlQYXJhbXMgPSBbJ2VuY29kaW5nJywgJ2RhdGEnLCAnY29udGVudFR5cGUnXTtcbiAgICB2YXIgc2NvcGVDb25maWcgPSB7XG4gICAgICAgIHVzZXI6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddLFxuICAgICAgICBncm91cDogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSxcbiAgICAgICAgcHJvamVjdDogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnXSxcbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlRmlsZW5hbWUgPSBmdW5jdGlvbiAoZmlsZW5hbWUpIHtcbiAgICAgICAgaWYgKCFmaWxlbmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdmaWxlbmFtZSBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlVXJsUGFyYW1zID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHBhcnRLZXlzID0gc2NvcGVDb25maWdbb3B0aW9ucy5zY29wZV07XG4gICAgICAgIGlmICghcGFydEtleXMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignc2NvcGUgcGFyYW1ldGVyIGlzIG5lZWRlZC4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgICQuZWFjaChwYXJ0S2V5cywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKCFvcHRpb25zW3RoaXNdKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMgKyAnIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICB2YXIgYnVpbGRVcmwgPSBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVVcmxQYXJhbXMob3B0aW9ucyk7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICB2YXIgcGFydHMgPSAkLm1hcChwYXJ0S2V5cywgZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbnNba2V5XTtcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChmaWxlbmFtZSkge1xuICAgICAgICAgICAgLy8gVGhpcyBwcmV2ZW50cyBhZGRpbmcgYSB0cmFpbGluZyAvIGluIHRoZSBVUkwgYXMgdGhlIEFzc2V0IEFQSVxuICAgICAgICAgICAgLy8gZG9lcyBub3Qgd29yayBjb3JyZWN0bHkgd2l0aCBpdFxuICAgICAgICAgICAgZmlsZW5hbWUgPSAnLycgKyBmaWxlbmFtZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcGFydHMuam9pbignLycpICsgZmlsZW5hbWU7XG4gICAgfTtcblxuICAgIC8vIFByaXZhdGUgZnVuY3Rpb24sIGFsbCByZXF1ZXN0cyBmb2xsb3cgYSBtb3JlIG9yIGxlc3Mgc2FtZSBhcHByb2FjaCB0b1xuICAgIC8vIHVzZSB0aGUgQXNzZXQgQVBJIGFuZCB0aGUgZGlmZmVyZW5jZSBpcyB0aGUgSFRUUCB2ZXJiXG4gICAgLy9cbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gYG1ldGhvZGAgKFJlcXVpcmVkKSBIVFRQIHZlcmJcbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlL3JlcGxhY2UvY3JlYXRlXG4gICAgLy8gQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICB2YXIgdXBsb2FkID0gZnVuY3Rpb24gKG1ldGhvZCwgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YWxpZGF0ZUZpbGVuYW1lKGZpbGVuYW1lKTtcbiAgICAgICAgLy8gbWFrZSBzdXJlIHRoZSBwYXJhbWV0ZXIgaXMgY2xlYW5cbiAgICAgICAgbWV0aG9kID0gbWV0aG9kLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBjb250ZW50VHlwZSA9IHBhcmFtcyBpbnN0YW5jZW9mIEZvcm1EYXRhID09PSB0cnVlID8gZmFsc2UgOiAnYXBwbGljYXRpb24vanNvbic7XG4gICAgICAgIGlmIChjb250ZW50VHlwZSA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nKSB7XG4gICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgYXNzZXRBcGlQYXJhbXMpO1xuICAgICAgICB9IGVsc2UgeyAvLyBlbHNlIHdlJ3JlIHNlbmRpbmcgZm9ybSBkYXRhIHdoaWNoIGdvZXMgZGlyZWN0bHkgaW4gcmVxdWVzdCBib2R5XG4gICAgICAgICAgICAvLyBGb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSB1cGxvYWRzIHRoZSBmaWxlbmFtZSBpcyBub3Qgc2V0IGluIHRoZSBVUkwsXG4gICAgICAgICAgICAvLyBpdCdzIGdldHRpbmcgcGlja2VkIGJ5IHRoZSBGb3JtRGF0YSBmaWVsZCBmaWxlbmFtZS5cbiAgICAgICAgICAgIGZpbGVuYW1lID0gbWV0aG9kID09PSAncG9zdCcgfHwgbWV0aG9kID09PSAncHV0JyA/ICcnIDogZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsLCBjb250ZW50VHlwZTogY29udGVudFR5cGUgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHBbbWV0aG9kXShwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgKiBDcmVhdGVzIGEgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLiBUaGUgc2VydmVyIHJldHVybnMgYW4gZXJyb3IgKHN0YXR1cyBjb2RlIGA0MDlgLCBjb25mbGljdCkgaWYgdGhlIGZpbGUgYWxyZWFkeSBleGlzdHMsIHNvXG4gICAgICAgICogY2hlY2sgZmlyc3Qgd2l0aCBhIGBsaXN0KClgIG9yIGEgYGdldCgpYC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gICAgICAgICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICAgICogICAgICAgICAgdXNlcklkOiAnJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gY3JlYXRlIGEgbmV3IGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSFJsYzNRZ1ptbHNaUzQ9JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlXCIgdHlwZT1cImZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAgICAgICAgKiAgICAgICAvLyA8L2Zvcm0+XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI2ZpbGVuYW1lJykudmFsKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgaW5wdXRDb250cm9sID0gJCgnI2ZpbGUnKVswXTtcbiAgICAgICAgKiAgICAgICAgICBkYXRhLmFwcGVuZCgnZmlsZScsIGlucHV0Q29udHJvbC5maWxlc1swXSwgZmlsZW5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgYWEuY3JlYXRlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byBjcmVhdGUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncG9zdCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSSwgZmV0Y2hpbmcgdGhlIGFzc2V0IGNvbnRlbnQuIChUbyBnZXQgYSBsaXN0XG4gICAgICAgICogb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLCB1c2UgYGxpc3QoKWAuKVxuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIHJldHJpZXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGdldFNlcnZpY2VPcHRpb25zID0gX3BpY2soc2VydmljZU9wdGlvbnMsIFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddKTtcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIGdldFNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybChmaWxlbmFtZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGxpc3Qgb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmxpc3QoeyBmdWxsVXJsOiB0cnVlIH0pLnRoZW4oZnVuY3Rpb24oZmlsZUxpc3Qpe1xuICAgICAgICAqICAgICAgICAgICBjb25zb2xlLmxvZygnYXJyYXkgb2YgZmlsZXMgPSAnLCBmaWxlTGlzdCk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnNjb3BlYCAoT3B0aW9uYWwpIFRoZSBzY29wZSAoYHVzZXJgLCBgZ3JvdXBgLCBgcHJvamVjdGApLlxuICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gYG9wdGlvbnMuZnVsbFVybGAgKE9wdGlvbmFsKSBEZXRlcm1pbmVzIGlmIHRoZSBsaXN0IG9mIGFzc2V0cyBpbiBhIHNjb3BlIGluY2x1ZGVzIHRoZSBjb21wbGV0ZSBVUkwgZm9yIGVhY2ggYXNzZXQgKGB0cnVlYCksIG9yIG9ubHkgdGhlIGZpbGUgbmFtZXMgb2YgdGhlIGFzc2V0cyAoYGZhbHNlYCkuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgbGlzdDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKCcnLCB1cmxPcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHVybE9wdGlvbnMsIHsgdXJsOiB1cmwgfSk7XG4gICAgICAgICAgICB2YXIgZnVsbFVybCA9IGdldE9wdGlvbnMuZnVsbFVybDtcblxuICAgICAgICAgICAgaWYgKCFmdWxsVXJsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBmdWxsUGF0aEZpbGVzID0gJC5tYXAoZmlsZXMsIGZ1bmN0aW9uIChmaWxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShmdWxsUGF0aEZpbGVzLCBtZSk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChkdGQucmVqZWN0KTtcblxuICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGFjZXMgYW4gZXhpc3RpbmcgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgZW5jb2RlZCB0ZXh0XG4gICAgICAgICogICAgICAgYWEucmVwbGFjZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSE5sWTI5dVpDQjBaWE4wSUdacGJHVXUnLFxuICAgICAgICAqICAgICAgICAgICBjb250ZW50VHlwZTogJ3RleHQvcGxhaW4nXG4gICAgICAgICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gYWx0ZXJuYXRpdmVseSwgcmVwbGFjZSBhbiBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInJlcGxhY2UtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJyZXBsYWNlLWZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlJlcGxhY2UgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3JlcGxhY2UtZmlsZScpLm9uKCdzdWJtaXQnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZmlsZW5hbWUgPSAkKCcjcmVwbGFjZS1maWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLnJlcGxhY2UoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSBiZWluZyByZXBsYWNlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgKE9wdGlvbmFsKSBCb2R5IHBhcmFtZXRlcnMgdG8gc2VuZCB0byB0aGUgQXNzZXQgQVBJLiBSZXF1aXJlZCBpZiB0aGUgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAsIG90aGVyd2lzZSBpZ25vcmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmVuY29kaW5nYCBFaXRoZXIgYEhFWGAgb3IgYEJBU0VfNjRgLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5kYXRhYCBUaGUgZW5jb2RlZCBkYXRhIGZvciB0aGUgZmlsZS4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuY29udGVudFR5cGVgIFRoZSBtaW1lIHR5cGUgb2YgdGhlIGZpbGUuIE9wdGlvbmFsLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICByZXBsYWNlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncHV0JywgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogRGVsZXRlcyBhIGZpbGUgZnJvbSB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmRlbGV0ZShzYW1wbGVGaWxlTmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGU6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgnZGVsZXRlJywgZmlsZW5hbWUsIHt9LCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhc3NldFVybDogZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICpcbiAqICMjQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2UgcHJvdmlkZXMgbWV0aG9kcyBmb3IgbG9nZ2luZyBpbiBhbmQgbG9nZ2luZyBvdXQuIE9uIGxvZ2luLCB0aGlzIHNlcnZpY2UgY3JlYXRlcyBhbmQgcmV0dXJucyBhIHVzZXIgYWNjZXNzIHRva2VuLlxuICpcbiAqIFVzZXIgYWNjZXNzIHRva2VucyBhcmUgcmVxdWlyZWQgZm9yIGVhY2ggY2FsbCB0byBFcGljZW50ZXIuIChTZWUgW1Byb2plY3QgQWNjZXNzXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pIGZvciBtb3JlIGluZm9ybWF0aW9uLilcbiAqXG4gKiBJZiB5b3UgbmVlZCBhZGRpdGlvbmFsIGZ1bmN0aW9uYWxpdHkgLS0gc3VjaCBhcyB0cmFja2luZyBzZXNzaW9uIGluZm9ybWF0aW9uLCBlYXNpbHkgcmV0cmlldmluZyB0aGUgdXNlciB0b2tlbiwgb3IgZ2V0dGluZyB0aGUgZ3JvdXBzIHRvIHdoaWNoIGFuIGVuZCB1c2VyIGJlbG9uZ3MgLS0gY29uc2lkZXIgdXNpbmcgdGhlIFtBdXRob3JpemF0aW9uIE1hbmFnZXJdKC4uL2F1dGgtbWFuYWdlci8pIGluc3RlYWQuXG4gKlxuICogICAgICB2YXIgYXV0aCA9IG5ldyBGLnNlcnZpY2UuQXV0aCgpO1xuICogICAgICBhdXRoLmxvZ2luKHsgdXNlck5hbWU6ICdqc21pdGhAYWNtZXNpbXVsYXRpb25zLmNvbScsXG4gKiAgICAgICAgICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnIH0pO1xuICogICAgICBhdXRoLmxvZ291dCgpO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJOYW1lOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwYXNzd29yZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBSZXF1aXJlZCBpZiB0aGUgYHVzZXJOYW1lYCBpcyBmb3IgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2F1dGhlbnRpY2F0aW9uJylcbiAgICB9KTtcbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9ncyB1c2VyIGluLCByZXR1cm5pbmcgdGhlIHVzZXIgYWNjZXNzIHRva2VuLlxuICAgICAgICAgKlxuICAgICAgICAgKiBJZiBubyBgdXNlck5hbWVgIG9yIGBwYXNzd29yZGAgd2VyZSBwcm92aWRlZCBpbiB0aGUgaW5pdGlhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMsIHRoZXkgYXJlIHJlcXVpcmVkIGluIHRoZSBgb3B0aW9uc2AgaGVyZS4gSWYgbm8gYGFjY291bnRgIHdhcyBwcm92aWRlZCBpbiB0aGUgaW5pdGlhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMgYW5kIHRoZSBgdXNlck5hbWVgIGlzIGZvciBhbiBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycyksIHRoZSBgYWNjb3VudGAgaXMgcmVxdWlyZWQgYXMgd2VsbC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBhdXRoLmxvZ2luKHtcbiAgICAgICAgICogICAgICAgICAgdXNlck5hbWU6ICdqc21pdGgnLFxuICAgICAgICAgKiAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyxcbiAgICAgICAgICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnIH0pXG4gICAgICAgICAqICAgICAgLnRoZW4oZnVuY3Rpb24gKHRva2VuKSB7XG4gICAgICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKFwidXNlciBhY2Nlc3MgdG9rZW4gaXM6IFwiLCB0b2tlbi5hY2Nlc3NfdG9rZW4pO1xuICAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2dpbjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHsgc3VjY2VzczogJC5ub29wIH0sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGlmICghaHR0cE9wdGlvbnMudXNlck5hbWUgfHwgIWh0dHBPcHRpb25zLnBhc3N3b3JkKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlc3AgPSB7IHN0YXR1czogNDAxLCBzdGF0dXNNZXNzYWdlOiAnTm8gdXNlcm5hbWUgb3IgcGFzc3dvcmQgc3BlY2lmaWVkLicgfTtcbiAgICAgICAgICAgICAgICBpZiAob3B0aW9ucy5lcnJvcikge1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmVycm9yLmNhbGwodGhpcywgcmVzcCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuICQuRGVmZXJyZWQoKS5yZWplY3QocmVzcCkucHJvbWlzZSgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcG9zdFBhcmFtcyA9IHtcbiAgICAgICAgICAgICAgICB1c2VyTmFtZTogaHR0cE9wdGlvbnMudXNlck5hbWUsXG4gICAgICAgICAgICAgICAgcGFzc3dvcmQ6IGh0dHBPcHRpb25zLnBhc3N3b3JkLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmIChodHRwT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgICAgICAgICAgLy9wYXNzIGluIG51bGwgZm9yIGFjY291bnQgdW5kZXIgb3B0aW9ucyBpZiB5b3UgZG9uJ3Qgd2FudCBpdCB0byBiZSBzZW50XG4gICAgICAgICAgICAgICAgcG9zdFBhcmFtcy5hY2NvdW50ID0gaHR0cE9wdGlvbnMuYWNjb3VudDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwb3N0UGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvZ3MgdXNlciBvdXQgZnJvbSBzcGVjaWZpZWQgYWNjb3VudHMuXG4gICAgICAgICAqIEVwaWNlbnRlciBsb2dvdXQgaXMgbm90IGltcGxlbWVudGVkIHlldCwgYWRkZWQgYSBkdW1teSBwcm9taXNlIHRoYXQgZ2V0cyBhdXRvbWF0aWNhbGx5IHJlc29sdmVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGF1dGgubG9nb3V0KCk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvZ291dDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBTZXJ2aWNlXG4gKlxuICogVGhlIEVwaWNlbnRlciBwbGF0Zm9ybSBwcm92aWRlcyBhIHB1c2ggY2hhbm5lbCwgd2hpY2ggYWxsb3dzIHlvdSB0byBwdWJsaXNoIGFuZCBzdWJzY3JpYmUgdG8gbWVzc2FnZXMgd2l0aGluIGEgW3Byb2plY3RdKC4uLy4uLy4uL2dsb3NzYXJ5LyNwcm9qZWN0cyksIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcyksIG9yIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS4gVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIENoYW5uZWwgU2VydmljZSBpcyBhIGJ1aWxkaW5nIGJsb2NrIGZvciB0aGlzIGZ1bmN0aW9uYWxpdHkuIEl0IGNyZWF0ZXMgYSBwdWJsaXNoLXN1YnNjcmliZSBvYmplY3QsIGFsbG93aW5nIHlvdSB0byBwdWJsaXNoIG1lc3NhZ2VzLCBzdWJzY3JpYmUgdG8gbWVzc2FnZXMsIG9yIHVuc3Vic2NyaWJlIGZyb20gbWVzc2FnZXMgZm9yIGEgZ2l2ZW4gJ3RvcGljJyBvbiBhIGAkLmNvbWV0ZGAgdHJhbnNwb3J0IGluc3RhbmNlLlxuICpcbiAqIFR5cGljYWxseSwgeW91IHVzZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSB0byBjcmVhdGUgb3IgcmV0cmlldmUgY2hhbm5lbHMsIHRoZW4gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UgYHN1YnNjcmliZSgpYCBhbmQgYHB1Ymxpc2goKWAgbWV0aG9kcyB0byBsaXN0ZW4gdG8gb3IgdXBkYXRlIGRhdGEuIChGb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIEVwaWNlbnRlcidzIHB1c2ggY2hhbm5lbCwgc2VlIHRoZSBpbnRyb2R1Y3Rvcnkgbm90ZXMgb24gdGhlIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIHBhZ2UuKVxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgU2VydmljZS4gU2VlIFtJbmNsdWRpbmcgRXBpY2VudGVyLmpzXSguLi8uLi8jaW5jbHVkZSkuXG4gKlxuICogVG8gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UsIGluc3RhbnRpYXRlIGl0LCB0aGVuIG1ha2UgY2FsbHMgdG8gYW55IG9mIHRoZSBtZXRob2RzIHlvdSBuZWVkLlxuICpcbiAqICAgICAgICB2YXIgY3MgPSBuZXcgRi5zZXJ2aWNlLkNoYW5uZWwoKTtcbiAqICAgICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcycsIHsgcHJpY2U6IDUwIH0pO1xuICpcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciBpbnN0YW50aWF0aW5nIGEgQ2hhbm5lbCBTZXJ2aWNlIGluY2x1ZGU6XG4gKlxuICogKiBgb3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLlxuICogKiBgb3B0aW9ucy5iYXNlYCBUaGUgYmFzZSB0b3BpYy4gVGhpcyBpcyBhZGRlZCBhcyBhIHByZWZpeCB0byBhbGwgZnVydGhlciB0b3BpY3MgeW91IHB1Ymxpc2ggb3Igc3Vic2NyaWJlIHRvIHdoaWxlIHdvcmtpbmcgd2l0aCB0aGlzIENoYW5uZWwgU2VydmljZS5cbiAqICogYG9wdGlvbnMudG9waWNSZXNvbHZlcmAgQSBmdW5jdGlvbiB0aGF0IHByb2Nlc3NlcyBhbGwgJ3RvcGljcycgcGFzc2VkIGludG8gdGhlIGBwdWJsaXNoYCBhbmQgYHN1YnNjcmliZWAgbWV0aG9kcy4gVGhpcyBpcyB1c2VmdWwgaWYgeW91IHdhbnQgdG8gaW1wbGVtZW50IHlvdXIgb3duIHNlcmlhbGl6ZSBmdW5jdGlvbnMgZm9yIGNvbnZlcnRpbmcgY3VzdG9tIG9iamVjdHMgdG8gdG9waWMgbmFtZXMuIFJldHVybnMgYSBTdHJpbmcuIEJ5IGRlZmF1bHQsIGl0IGp1c3QgZWNob2VzIHRoZSB0b3BpYy5cbiAqICogYG9wdGlvbnMudHJhbnNwb3J0YCBUaGUgaW5zdGFuY2Ugb2YgYCQuY29tZXRkYCB0byBob29rIG9udG8uIFNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZCBvbiBjb21ldGQuXG4gKi9cbnZhciBDaGFubmVsID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBiYXNlIHRvcGljLiBUaGlzIGlzIGFkZGVkIGFzIGEgcHJlZml4IHRvIGFsbCBmdXJ0aGVyIHRvcGljcyB5b3UgcHVibGlzaCBvciBzdWJzY3JpYmUgdG8gd2hpbGUgd29ya2luZyB3aXRoIHRoaXMgQ2hhbm5lbCBTZXJ2aWNlLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYmFzZTogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEEgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgYWxsICd0b3BpY3MnIHBhc3NlZCBpbnRvIHRoZSBgcHVibGlzaGAgYW5kIGBzdWJzY3JpYmVgIG1ldGhvZHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGltcGxlbWVudCB5b3VyIG93biBzZXJpYWxpemUgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGN1c3RvbSBvYmplY3RzIHRvIHRvcGljIG5hbWVzLiBCeSBkZWZhdWx0LCBpdCBqdXN0IGVjaG9lcyB0aGUgdG9waWMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICogYHRvcGljYCBUb3BpYyB0byBwYXJzZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqICpTdHJpbmcqOiBUaGlzIGZ1bmN0aW9uIHNob3VsZCByZXR1cm4gYSBzdHJpbmcgdG9waWMuXG4gICAgICAgICAqXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHRvcGljUmVzb2x2ZXI6IGZ1bmN0aW9uICh0b3BpYykge1xuICAgICAgICAgICAgcmV0dXJuIHRvcGljO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgaW5zdGFuY2Ugb2YgYCQuY29tZXRkYCB0byBob29rIG9udG8uXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IG51bGxcbiAgICB9O1xuICAgIHRoaXMuY2hhbm5lbE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xufTtcblxudmFyIG1ha2VOYW1lID0gZnVuY3Rpb24gKGNoYW5uZWxOYW1lLCB0b3BpYykge1xuICAgIC8vUmVwbGFjZSB0cmFpbGluZy9kb3VibGUgc2xhc2hlc1xuICAgIHZhciBuZXdOYW1lID0gKGNoYW5uZWxOYW1lID8gKGNoYW5uZWxOYW1lICsgJy8nICsgdG9waWMpIDogdG9waWMpLnJlcGxhY2UoL1xcL1xcLy9nLCAnLycpLnJlcGxhY2UoL1xcLyQvLCcnKTtcbiAgICByZXR1cm4gbmV3TmFtZTtcbn07XG5cblxuQ2hhbm5lbC5wcm90b3R5cGUgPSAkLmV4dGVuZChDaGFubmVsLnByb3RvdHlwZSwge1xuXG4gICAgLy8gZnV0dXJlIGZ1bmN0aW9uYWxpdHk6XG4gICAgLy8gICAgICAvLyBTZXQgdGhlIGNvbnRleHQgZm9yIHRoZSBjYWxsYmFja1xuICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4nLCBmdW5jdGlvbiAoKSB7IHRoaXMuaW5uZXJIVE1MID0gJ1RyaWdnZXJlZCd9LCBkb2N1bWVudC5ib2R5KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBDb250cm9sIHRoZSBvcmRlciBvZiBvcGVyYXRpb25zIGJ5IHNldHRpbmcgdGhlIGBwcmlvcml0eWBcbiAgICAgLy8gICAgICBjcy5zdWJzY3JpYmUoJ3J1bicsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDl9KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBPbmx5IGV4ZWN1dGUgdGhlIGNhbGxiYWNrLCBgY2JgLCBpZiB0aGUgdmFsdWUgb2YgdGhlIGBwcmljZWAgdmFyaWFibGUgaXMgNTBcbiAgICAgLy8gICAgICBjcy5zdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6IDUwfSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIGdyZWF0ZXIgdGhhbiA1MFxuICAgICAvLyAgICAgIHN1YnNjcmliZSgncnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDMwLCB2YWx1ZTogJz41MCd9KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBPbmx5IGV4ZWN1dGUgdGhlIGNhbGxiYWNrLCBgY2JgLCBpZiB0aGUgdmFsdWUgb2YgdGhlIGBwcmljZWAgdmFyaWFibGUgaXMgZXZlblxuICAgICAvLyAgICAgIHN1YnNjcmliZSgncnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDMwLCB2YWx1ZTogZnVuY3Rpb24gKHZhbCkge3JldHVybiB2YWwgJSAyID09PSAwfX0pO1xuXG5cbiAgICAvKipcbiAgICAgKiBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBhIHRvcGljLlxuICAgICAqXG4gICAgICogVGhlIHRvcGljIHNob3VsZCBpbmNsdWRlIHRoZSBmdWxsIHBhdGggb2YgdGhlIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzKSwgcHJvamVjdCBpZCwgYW5kIGdyb3VwIG5hbWUuIChJbiBtb3N0IGNhc2VzLCBpdCBpcyBzaW1wbGVyIHRvIHVzZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSBpbnN0ZWFkLCBpbiB3aGljaCBjYXNlIHRoaXMgaXMgY29uZmlndXJlZCBmb3IgeW91LilcbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGVzKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIGNiID0gZnVuY3Rpb24odmFsKSB7IGNvbnNvbGUubG9nKHZhbC5kYXRhKTsgfTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSB0b3AtbGV2ZWwgJ3J1bicgdG9waWNcbiAgICAgKiAgICAgIGNzLnN1YnNjcmliZSgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gY2hpbGRyZW4gb2YgdGhlICdydW4nIHRvcGljLiBOb3RlIHRoaXMgd2lsbCBhbHNvIGJlIHRyaWdnZXJlZCBmb3IgY2hhbmdlcyB0byBydW4ueC55LnouXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vKicsIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYm90aCB0aGUgdG9wLWxldmVsICdydW4nIHRvcGljIGFuZCBpdHMgY2hpbGRyZW5cbiAgICAgKiAgICAgIGNzLnN1YnNjcmliZShbJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLFxuICAgICAqICAgICAgICAgICcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuLyonXSwgY2IpO1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBhIHBhcnRpY3VsYXIgdmFyaWFibGVcbiAgICAgKiAgICAgIHN1YnNjcmliZSgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYik7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKlN0cmluZyogUmV0dXJucyBhIHRva2VuIHlvdSBjYW4gbGF0ZXIgdXNlIHRvIHVuc3Vic2NyaWJlLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8QXJyYXl9ICAgYHRvcGljYCAgICBMaXN0IG9mIHRvcGljcyB0byBsaXN0ZW4gZm9yIGNoYW5nZXMgb24uXG4gICAgICogQHBhcmFtICB7RnVuY3Rpb259IGBjYWxsYmFja2AgQ2FsbGJhY2sgZnVuY3Rpb24gdG8gZXhlY3V0ZS4gQ2FsbGJhY2sgaXMgY2FsbGVkIHdpdGggc2lnbmF0dXJlIGAoZXZ0LCBwYXlsb2FkLCBtZXRhZGF0YSlgLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gICBgY29udGV4dGAgIENvbnRleHQgaW4gd2hpY2ggdGhlIGBjYWxsYmFja2AgaXMgZXhlY3V0ZWQuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSAgIGBvcHRpb25zYCAgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKiBAcGFyYW0gIHtOdW1iZXJ9ICAgYG9wdGlvbnMucHJpb3JpdHlgICBVc2VkIHRvIGNvbnRyb2wgb3JkZXIgb2Ygb3BlcmF0aW9ucy4gRGVmYXVsdHMgdG8gMC4gQ2FuIGJlIGFueSArdmUgb3IgLXZlIG51bWJlci5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8TnVtYmVyfEZ1bmN0aW9ufSAgIGBvcHRpb25zLnZhbHVlYCBUaGUgYGNhbGxiYWNrYCBpcyBvbmx5IHRyaWdnZXJlZCBpZiB0aGlzIGNvbmRpdGlvbiBtYXRjaGVzLiBTZWUgZXhhbXBsZXMgZm9yIGRldGFpbHMuXG4gICAgICpcbiAgICAgKi9cbiAgICBzdWJzY3JpYmU6IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcblxuICAgICAgICB2YXIgdG9waWNzID0gW10uY29uY2F0KHRvcGljKTtcbiAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgdmFyIHN1YnNjcmlwdGlvbklkcyA9IFtdO1xuICAgICAgICB2YXIgb3B0cyA9IG1lLmNoYW5uZWxPcHRpb25zO1xuXG4gICAgICAgIG9wdHMudHJhbnNwb3J0LmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICQuZWFjaCh0b3BpY3MsIGZ1bmN0aW9uIChpbmRleCwgdG9waWMpIHtcbiAgICAgICAgICAgICAgICB0b3BpYyA9IG1ha2VOYW1lKG9wdHMuYmFzZSwgb3B0cy50b3BpY1Jlc29sdmVyKHRvcGljKSk7XG4gICAgICAgICAgICAgICAgc3Vic2NyaXB0aW9uSWRzLnB1c2gob3B0cy50cmFuc3BvcnQuc3Vic2NyaWJlKHRvcGljLCBjYWxsYmFjaykpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKHN1YnNjcmlwdGlvbklkc1sxXSA/IHN1YnNjcmlwdGlvbklkcyA6IHN1YnNjcmlwdGlvbklkc1swXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFB1Ymxpc2ggZGF0YSB0byBhIHRvcGljLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlcyoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIFNlbmQgZGF0YSB0byBhbGwgc3Vic2NyaWJlcnMgb2YgdGhlICdydW4nIHRvcGljXG4gICAgICogICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJywgeyBjb21wbGV0ZWQ6IGZhbHNlIH0pO1xuICAgICAqXG4gICAgICogICAgICAvLyBTZW5kIGRhdGEgdG8gYWxsIHN1YnNjcmliZXJzIG9mIHRoZSAncnVuL3ZhcmlhYmxlcycgdG9waWNcbiAgICAgKiAgICAgIGNzLnB1Ymxpc2goJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzJywgeyBwcmljZTogNTAgfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgdG9waWNgIFRvcGljIHRvIHB1Ymxpc2ggdG8uXG4gICAgICogQHBhcmFtICB7Kn0gYGRhdGFgICBEYXRhIHRvIHB1Ymxpc2ggdG8gdG9waWMuXG4gICAgICpcbiAgICAgKi9cbiAgICBwdWJsaXNoOiBmdW5jdGlvbiAodG9waWMsIGRhdGEpIHtcbiAgICAgICAgdmFyIHRvcGljcyA9IFtdLmNvbmNhdCh0b3BpYyk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciByZXR1cm5PYmpzID0gW107XG4gICAgICAgIHZhciBvcHRzID0gbWUuY2hhbm5lbE9wdGlvbnM7XG5cblxuICAgICAgICBvcHRzLnRyYW5zcG9ydC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkLmVhY2godG9waWNzLCBmdW5jdGlvbiAoaW5kZXgsIHRvcGljKSB7XG4gICAgICAgICAgICAgICAgdG9waWMgPSBtYWtlTmFtZShvcHRzLmJhc2UsIG9wdHMudG9waWNSZXNvbHZlcih0b3BpYykpO1xuICAgICAgICAgICAgICAgIGlmICh0b3BpYy5jaGFyQXQodG9waWMubGVuZ3RoIC0gMSkgPT09ICcqJykge1xuICAgICAgICAgICAgICAgICAgICB0b3BpYyA9IHRvcGljLnJlcGxhY2UoL1xcKiskLywgJycpO1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1lvdSBjYW4gY2Fubm90IHB1Ymxpc2ggdG8gY2hhbm5lbHMgd2l0aCB3aWxkY2FyZHMuIFB1Ymxpc2hpbmcgdG8gJywgdG9waWMsICdpbnN0ZWFkJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybk9ianMucHVzaChvcHRzLnRyYW5zcG9ydC5wdWJsaXNoKHRvcGljLCBkYXRhKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiAocmV0dXJuT2Jqc1sxXSA/IHJldHVybk9ianMgOiByZXR1cm5PYmpzWzBdKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVW5zdWJzY3JpYmUgZnJvbSBjaGFuZ2VzIHRvIGEgdG9waWMuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBjcy51bnN1YnNjcmliZSgnc2FtcGxlVG9rZW4nKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgdG9rZW5gIFRoZSB0b2tlbiBmb3IgdG9waWMgaXMgcmV0dXJuZWQgd2hlbiB5b3UgaW5pdGlhbGx5IHN1YnNjcmliZS4gUGFzcyBpdCBoZXJlIHRvIHVuc3Vic2NyaWJlIGZyb20gdGhhdCB0b3BpYy5cbiAgICAgKi9cbiAgICB1bnN1YnNjcmliZTogZnVuY3Rpb24gKHRva2VuKSB7XG4gICAgICAgIHRoaXMuY2hhbm5lbE9wdGlvbnMudHJhbnNwb3J0LnVuc3Vic2NyaWJlKHRva2VuKTtcbiAgICAgICAgcmV0dXJuIHRva2VuO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdGFydCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKlxuICAgICAqIFN1cHBvcnRlZCBldmVudHMgYXJlOiBgY29ubmVjdGAsIGBkaXNjb25uZWN0YCwgYHN1YnNjcmliZWAsIGB1bnN1YnNjcmliZWAsIGBwdWJsaXNoYCwgYGVycm9yYC5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICovXG4gICAgb246IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9uLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0b3AgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICovXG4gICAgb2ZmOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vZmYuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVHJpZ2dlciBldmVudHMgYW5kIGV4ZWN1dGUgaGFuZGxlcnMuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vdHJpZ2dlci8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vdHJpZ2dlci8uXG4gICAgICovXG4gICAgdHJpZ2dlcjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlci5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH1cblxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbDtcbiIsIi8qKlxuICogQGNsYXNzIENvbmZpZ3VyYXRpb25TZXJ2aWNlXG4gKlxuICogQWxsIHNlcnZpY2VzIHRha2UgaW4gYSBjb25maWd1cmF0aW9uIHNldHRpbmdzIG9iamVjdCB0byBjb25maWd1cmUgdGhlbXNlbHZlcy4gQSBKUyBoYXNoIHt9IGlzIGEgdmFsaWQgY29uZmlndXJhdGlvbiBvYmplY3QsIGJ1dCBvcHRpb25hbGx5IHlvdSBjYW4gdXNlIHRoZSBjb25maWd1cmF0aW9uIHNlcnZpY2UgdG8gdG9nZ2xlIGNvbmZpZ3MgYmFzZWQgb24gdGhlIGVudmlyb25tZW50XG4gKlxuICogQGV4YW1wbGVcbiAqICAgICB2YXIgY3MgPSByZXF1aXJlKCdjb25maWd1cmF0aW9uLXNlcnZpY2UnKSh7XG4gKiAgICAgICAgICBkZXY6IHsgLy9lbnZpcm9ubWVudFxuICAgICAgICAgICAgICAgIHBvcnQ6IDMwMDAsXG4gICAgICAgICAgICAgICAgaG9zdDogJ2xvY2FsaG9zdCcsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgcHJvZDoge1xuICAgICAgICAgICAgICAgIHBvcnQ6IDgwODAsXG4gICAgICAgICAgICAgICAgaG9zdDogJ2FwaS5mb3Jpby5jb20nLFxuICAgICAgICAgICAgICAgIGxvZ0xldmVsOiAnbm9uZSdcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBsb2dMZXZlbDogJ0RFQlVHJyAvL2dsb2JhbFxuICogICAgIH0pO1xuICpcbiAqICAgICAgY3MuZ2V0KCdsb2dMZXZlbCcpOyAvL3JldHVybnMgJ0RFQlVHJ1xuICpcbiAqICAgICAgY3Muc2V0RW52KCdkZXYnKTtcbiAqICAgICAgY3MuZ2V0KCdsb2dMZXZlbCcpOyAvL3JldHVybnMgJ0RFQlVHJ1xuICpcbiAqICAgICAgY3Muc2V0RW52KCdwcm9kJyk7XG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdub25lJ1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgdXJsU2VydmljZSA9IHJlcXVpcmUoJy4vdXJsLWNvbmZpZy1zZXJ2aWNlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vVE9ETzogRW52aXJvbm1lbnRzXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICBsb2dMZXZlbDogJ05PTkUnXG4gICAgfTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgc2VydmljZU9wdGlvbnMuc2VydmVyID0gdXJsU2VydmljZShzZXJ2aWNlT3B0aW9ucy5zZXJ2ZXIpO1xuXG4gICAgcmV0dXJuIHtcblxuICAgICAgICBkYXRhOiBzZXJ2aWNlT3B0aW9ucyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IHRoZSBlbnZpcm9ubWVudCBrZXkgdG8gZ2V0IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmcm9tXG4gICAgICAgICAqIEBwYXJhbSB7IHN0cmluZ30gZW52XG4gICAgICAgICAqL1xuICAgICAgICBzZXRFbnY6IGZ1bmN0aW9uIChlbnYpIHtcblxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ30gcHJvcGVydHkgb3B0aW9uYWxcbiAgICAgICAgICogQHJldHVybiB7Kn0gICAgICAgICAgVmFsdWUgb2YgcHJvcGVydHkgaWYgc3BlY2lmaWVkLCB0aGUgZW50aXJlIGNvbmZpZyBvYmplY3Qgb3RoZXJ3aXNlXG4gICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChwcm9wZXJ0eSkge1xuICAgICAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zW3Byb3BlcnR5XTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2V0IGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8T2JqZWN0fSBrZXkgaWYgYSBrZXkgaXMgcHJvdmlkZWQsIHNldCBhIGtleSB0byB0aGF0IHZhbHVlLiBPdGhlcndpc2UgbWVyZ2Ugb2JqZWN0IHdpdGggY3VycmVudCBjb25maWdcbiAgICAgICAgICogQHBhcmFtICB7Kn0gdmFsdWUgIHZhbHVlIGZvciBwcm92aWRlZCBrZXlcbiAgICAgICAgICovXG4gICAgICAgIHNldDogZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH07XG59O1xuXG4iLCIvKipcbiAqICMjRGF0YSBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBEYXRhIEFQSSBTZXJ2aWNlIGFsbG93cyB5b3UgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCBtYW5pcHVsYXRlIGRhdGEgcmVsYXRlZCB0byBhbnkgb2YgeW91ciBwcm9qZWN0cy4gRGF0YSBhcmUgb3JnYW5pemVkIGluIGNvbGxlY3Rpb25zLiBFYWNoIGNvbGxlY3Rpb24gY29udGFpbnMgYSBkb2N1bWVudDsgZWFjaCBlbGVtZW50IG9mIHRoaXMgdG9wLWxldmVsIGRvY3VtZW50IGlzIGEgSlNPTiBvYmplY3QuIChTZWUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBvbiB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pLilcbiAqXG4gKiBBbGwgQVBJIGNhbGxzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBEYXRhIEFQSSBTZXJ2aWNlIGRlZmF1bHRzLiBJbiBwYXJ0aWN1bGFyLCB0aGVyZSBhcmUgdGhyZWUgcmVxdWlyZWQgcGFyYW1ldGVycyB3aGVuIHlvdSBpbnN0YW50aWF0ZSB0aGUgRGF0YSBTZXJ2aWNlOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKiAqIGByb290YDogVGhlIHRoZSBuYW1lIG9mIHRoZSBjb2xsZWN0aW9uLiBJZiB5b3UgaGF2ZSBtdWx0aXBsZSBjb2xsZWN0aW9ucyB3aXRoaW4gZWFjaCBvZiB5b3VyIHByb2plY3RzLCB5b3UgY2FuIGFsc28gcGFzcyB0aGUgY29sbGVjdGlvbiBuYW1lIGFzIGFuIG9wdGlvbiBmb3IgZWFjaCBjYWxsLlxuICpcbiAqICAgICAgIHZhciBkcyA9IG5ldyBGLnNlcnZpY2UuRGF0YSh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgcm9vdDogJ3N1cnZleS1yZXNwb25zZXMnLFxuICogICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMiwgJ3F1ZXN0aW9uMic6IDEwLFxuICogICAgICAgICAgJ3F1ZXN0aW9uMyc6IGZhbHNlLCAncXVlc3Rpb240JzogJ3NvbWV0aW1lcycgfSApO1xuICogICAgICAgZHMuc2F2ZUFzKCd1c2VyMicsXG4gKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAzLCAncXVlc3Rpb24yJzogOCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiB0cnVlLCAncXVlc3Rpb240JzogJ2Fsd2F5cycgfSApO1xuICogICAgICAgZHMucXVlcnkoJycseyAncXVlc3Rpb24yJzogeyAnJGd0JzogOX0gfSk7XG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGByb290YCwgdGhlIERhdGEgU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYW1lIG9mIGNvbGxlY3Rpb24uIERlZmF1bHRzIHRvIGAvYCwgdGhhdCBpcywgdGhlIHJvb3QgbGV2ZWwgb2YgeW91ciBwcm9qZWN0IGF0IGBmb3Jpby5jb20vYXBwL3lvdXItYWNjb3VudC1pZC95b3VyLXByb2plY3QtaWQvYC4gUmVxdWlyZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICByb290OiAnLycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3Igb3BlcmF0aW9ucyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiBzdG9yZS5nZXQoJ2VwaWNlbnRlci5wcm9qZWN0LnRva2VuJykgfHwgJycsXG5cbiAgICAgICAgZG9tYWluOiAnZm9yaW8uY29tJyxcblxuICAgICAgICAvL09wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXJcbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uIChrZXksIHJvb3QpIHtcbiAgICAgICAgaWYgKCFyb290KSB7XG4gICAgICAgICAgICByb290ID0gc2VydmljZU9wdGlvbnMucm9vdDtcbiAgICAgICAgfVxuICAgICAgICB2YXIgdXJsID0gdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2RhdGEnKSArIHF1dGlsLmFkZFRyYWlsaW5nU2xhc2gocm9vdCk7XG4gICAgICAgIGlmIChrZXkpIHtcbiAgICAgICAgICAgIHVybCs9IHF1dGlsLmFkZFRyYWlsaW5nU2xhc2goa2V5KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsO1xuICAgIH07XG5cbiAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogZ2V0VVJMXG4gICAgfSk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIGh0dHBPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2VhcmNoIGZvciBkYXRhIHdpdGhpbiBhIGNvbGxlY3Rpb24uXG4gICAgICAgICAqXG4gICAgICAgICAqIFNlYXJjaGluZyB1c2luZyBjb21wYXJpc29uIG9yIGxvZ2ljYWwgb3BlcmF0b3JzIChhcyBvcHBvc2VkIHRvIGV4YWN0IG1hdGNoZXMpIHJlcXVpcmVzIE1vbmdvREIgc3ludGF4LiBTZWUgdGhlIHVuZGVybHlpbmcgW0RhdGEgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvZGF0YV9hcGkvI3NlYXJjaGluZykgZm9yIGFkZGl0aW9uYWwgZGV0YWlscy5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVxdWVzdCBhbGwgZGF0YSBhc3NvY2lhdGVkIHdpdGggZG9jdW1lbnQgJ3VzZXIxJ1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGV4YWN0IG1hdGNoaW5nOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uIHdoZXJlICdxdWVzdGlvbjInIGlzIDlcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAncXVlc3Rpb24yJzogOX0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGNvbXBhcmlzb24gb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgZ3JlYXRlciB0aGFuIDlcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAncXVlc3Rpb24yJzogeyAnJGd0JzogOX0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbG9naWNhbCBvcGVyYXRvcnM6XG4gICAgICAgICAqICAgICAgLy8gcmVxdWVzdCBhbGwgZG9jdW1lbnRzIGluIGNvbGxlY3Rpb25cbiAgICAgICAgICogICAgICAvLyB3aGVyZSAncXVlc3Rpb24yJyBpcyBsZXNzIHRoYW4gMTAsIGFuZCAncXVlc3Rpb24zJyBpcyBmYWxzZVxuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICckYW5kJzogWyB7ICdxdWVzdGlvbjInOiB7ICckbHQnOjEwfSB9LCB7ICdxdWVzdGlvbjMnOiBmYWxzZSB9XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZWd1bGFyIGV4cHJlc3NzaW9uczogdXNlIGFueSBQZXJsLWNvbXBhdGlibGUgcmVndWxhciBleHByZXNzaW9uc1xuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uNScgY29udGFpbnMgdGhlIHN0cmluZyAnLipkYXknXG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uNSc6IHsgJyRyZWdleCc6ICcuKmRheScgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBrZXlgIFRoZSBuYW1lIG9mIHRoZSBkb2N1bWVudCB0byBzZWFyY2guIFBhc3MgdGhlIGVtcHR5IHN0cmluZyAoJycpIHRvIHNlYXJjaCB0aGUgZW50aXJlIGNvbGxlY3Rpb24uXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcXVlcnlgIFRoZSBxdWVyeSBvYmplY3QuIEZvciBleGFjdCBtYXRjaGluZywgdGhpcyBvYmplY3QgY29udGFpbnMgdGhlIGZpZWxkIG5hbWUgYW5kIGZpZWxkIHZhbHVlIHRvIG1hdGNoLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gY29tcGFyaXNvbiwgdGhpcyBvYmplY3QgY29udGFpbnMgdGhlIGZpZWxkIG5hbWUgYW5kIHRoZSBjb21wYXJpc29uIGV4cHJlc3Npb24uIEZvciBtYXRjaGluZyBiYXNlZCBvbiBsb2dpY2FsIG9wZXJhdG9ycywgdGhpcyBvYmplY3QgY29udGFpbnMgYW4gZXhwcmVzc2lvbiB1c2luZyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGV4YW1wbGVzLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKGtleSwgcXVlcnksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBxOiBxdWVyeSB9LCBvdXRwdXRNb2RpZmllcik7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhbiBhbm9ueW1vdXMgZG9jdW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiAoRG9jdW1lbnRzIGFyZSB0b3AtbGV2ZWwgZWxlbWVudHMgd2l0aGluIGEgY29sbGVjdGlvbi4gQ29sbGVjdGlvbnMgbXVzdCBiZSB1bmlxdWUgd2l0aGluIHRoaXMgYWNjb3VudCAodGVhbSBvciBwZXJzb25hbCBhY2NvdW50KSBhbmQgcHJvamVjdCBhbmQgYXJlIHNldCB3aXRoIHRoZSBgcm9vdGAgZmllbGQgaW4gdGhlIGBvcHRpb25gIHBhcmFtZXRlci4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLykgZm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMuc2F2ZSgncXVlc3Rpb24xJywgJ3llcycpO1xuICAgICAgICAgKiAgICAgIGRzLnNhdmUoe3F1ZXN0aW9uMToneWVzJywgcXVlc3Rpb24yOiAzMiB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHsgbmFtZTonSm9obicsIGNsYXNzTmFtZTogJ0NTMTAxJyB9LCB7IHJvb3Q6ICdzdHVkZW50cycgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYGtleWAgSWYgYGtleWAgaXMgYSBzdHJpbmcsIGl0IGlzIHRoZSBpZCBvZiB0aGUgZWxlbWVudCB0byBzYXZlIChjcmVhdGUpIGluIHRoaXMgZG9jdW1lbnQuIElmIGBrZXlgIGlzIGFuIG9iamVjdCwgdGhlIG9iamVjdCBpcyB0aGUgZGF0YSB0byBzYXZlIChjcmVhdGUpIGluIHRoaXMgZG9jdW1lbnQuIEluIGJvdGggY2FzZXMsIHRoZSBpZCBmb3IgdGhlIGRvY3VtZW50IGlzIGdlbmVyYXRlZCBhdXRvbWF0aWNhbGx5LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUuIElmIGBrZXlgIGlzIGEgc3RyaW5nLCB0aGlzIGlzIHRoZSB2YWx1ZSB0byBzYXZlLiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSB2YWx1ZShzKSB0byBzYXZlIGFyZSBhbHJlYWR5IHBhcnQgb2YgYGtleWAgYW5kIHRoaXMgYXJndW1lbnQgaXMgbm90IHJlcXVpcmVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzYXZlOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGF0dHJzO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBrZXkgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbHVlO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAoYXR0cnMgPSB7fSlba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTCgnJywgaHR0cE9wdGlvbnMucm9vdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBkYXRhIHRvIGEgbmFtZWQgZG9jdW1lbnQgb3IgZWxlbWVudCB3aXRoaW4gdGhlIGNvbGxlY3Rpb24uIFRoZSBgcm9vdGAgb2YgdGhlIGNvbGxlY3Rpb24gbXVzdCBiZSBzcGVjaWZpZWQgc2VwYXJhdGVseSBpbiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGVpdGhlciBhcyBwYXJ0IG9mIHRoZSBjYWxsIG9yIGFzIHBhcnQgb2YgdGhlIGluaXRpYWxpemF0aW9uIG9mIGRzLlxuICAgICAgICAgKlxuICAgICAgICAgKiAoRG9jdW1lbnRzIGFyZSB0b3AtbGV2ZWwgZWxlbWVudHMgd2l0aGluIGEgY29sbGVjdGlvbi4gQ29sbGVjdGlvbnMgbXVzdCBiZSB1bmlxdWUgd2l0aGluIHRoaXMgYWNjb3VudCAodGVhbSBvciBwZXJzb25hbCBhY2NvdW50KSBhbmQgcHJvamVjdCBhbmQgYXJlIHNldCB3aXRoIHRoZSBgcm9vdGAgZmllbGQgaW4gdGhlIGBvcHRpb25gIHBhcmFtZXRlci4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLykgZm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCd1c2VyMScsXG4gICAgICAgICAqICAgICAgICAgIHsgJ3F1ZXN0aW9uMSc6IDIsICdxdWVzdGlvbjInOiAxMCxcbiAgICAgICAgICogICAgICAgICAgICdxdWVzdGlvbjMnOiBmYWxzZSwgJ3F1ZXN0aW9uNCc6ICdzb21ldGltZXMnIH0gKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ3N0dWRlbnQxJyxcbiAgICAgICAgICogICAgICAgICAgeyBmaXJzdE5hbWU6ICdqb2huJywgbGFzdE5hbWU6ICdzbWl0aCcgfSxcbiAgICAgICAgICogICAgICAgICAgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygnbWdtdDEwMC9ncm91cEInLFxuICAgICAgICAgKiAgICAgICAgICB7IHNjZW5hcmlvWWVhcjogJzIwMTUnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ215Y2xhc3NlcycgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBJZCBvZiB0aGUgZG9jdW1lbnQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgdmFsdWVgIChPcHRpb25hbCkgVGhlIGRhdGEgdG8gc2F2ZSwgaW4ga2V5OnZhbHVlIHBhaXJzLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzYXZlQXM6IGZ1bmN0aW9uIChrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnB1dCh2YWx1ZSwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgZGF0YSBmb3IgYSBzcGVjaWZpYyBkb2N1bWVudCBvciBmaWVsZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMScpO1xuICAgICAgICAgKiAgICAgIGRzLmxvYWQoJ3VzZXIxL3F1ZXN0aW9uMycpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBga2V5YCBUaGUgaWQgb2YgdGhlIGRhdGEgdG8gcmV0dXJuLiBDYW4gYmUgdGhlIGlkIG9mIGEgZG9jdW1lbnQsIG9yIGEgcGF0aCB0byBkYXRhIHdpdGhpbiB0aGF0IGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKGtleSwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5LCBodHRwT3B0aW9ucy5yb290KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChvdXRwdXRNb2RpZmllciwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIGRhdGEgZnJvbSBjb2xsZWN0aW9uLiBPbmx5IGRvY3VtZW50cyAodG9wLWxldmVsIGVsZW1lbnRzIGluIGVhY2ggY29sbGVjdGlvbikgY2FuIGJlIGRlbGV0ZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICBkcy5yZW1vdmUoJ3VzZXIxJyk7XG4gICAgICAgICAqXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfEFycmF5fSBga2V5c2AgVGhlIGlkIG9mIHRoZSBkb2N1bWVudCB0byByZW1vdmUgZnJvbSB0aGlzIGNvbGxlY3Rpb24sIG9yIGFuIGFycmF5IG9mIHN1Y2ggaWRzLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXlzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHBhcmFtcztcbiAgICAgICAgICAgIGlmICgkLmlzQXJyYXkoa2V5cykpIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSB7IGlkOiBrZXlzIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHBhcmFtcyA9ICcnO1xuICAgICAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXlzLCBodHRwT3B0aW9ucy5yb290KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBodHRwLmRlbGV0ZShwYXJhbXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVwaWNlbnRlciBkb2Vzbid0IGFsbG93IG51a2luZyBjb2xsZWN0aW9uc1xuICAgICAgICAvLyAgICAgLyoqXG4gICAgICAgIC8vICAgICAgKiBSZW1vdmVzIGNvbGxlY3Rpb24gYmVpbmcgcmVmZXJlbmNlZFxuICAgICAgICAvLyAgICAgICogQHJldHVybiBudWxsXG4gICAgICAgIC8vICAgICAgKi9cbiAgICAgICAgLy8gICAgIGRlc3Ryb3k6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIC8vICAgICAgICAgcmV0dXJuIHRoaXMucmVtb3ZlKCcnLCBvcHRpb25zKTtcbiAgICAgICAgLy8gICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI01lbWJlciBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBNZW1iZXIgQVBJIEFkYXB0ZXIgcHJvdmlkZXMgbWV0aG9kcyB0byBsb29rIHVwIGluZm9ybWF0aW9uIGFib3V0IGVuZCB1c2VycyBmb3IgeW91ciBwcm9qZWN0IGFuZCBob3cgdGhleSBhcmUgZGl2aWRlZCBhY3Jvc3MgZ3JvdXBzLiBJdCBpcyBiYXNlZCBvbiBxdWVyeSBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbTWVtYmVyIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL3VzZXJfbWFuYWdlbWVudC9tZW1iZXIvKS5cbiAqXG4gKiBUaGlzIGlzIG9ubHkgbmVlZGVkIGZvciBBdXRoZW50aWNhdGVkIHByb2plY3RzLCB0aGF0IGlzLCB0ZWFtIHByb2plY3RzIHdpdGggW2VuZCB1c2VycyBhbmQgZ3JvdXBzXSguLi8uLi8uLi9ncm91cHNfYW5kX2VuZF91c2Vycy8pLiBGb3IgZXhhbXBsZSwgaWYgc29tZSBvZiB5b3VyIGVuZCB1c2VycyBhcmUgZmFjaWxpdGF0b3JzLCBvciBpZiB5b3VyIGVuZCB1c2VycyBzaG91bGQgYmUgdHJlYXRlZCBkaWZmZXJlbnRseSBiYXNlZCBvbiB3aGljaCBncm91cCB0aGV5IGFyZSBpbiwgdXNlIHRoZSBNZW1iZXIgQVBJIHRvIGZpbmQgdGhhdCBpbmZvcm1hdGlvbi5cbiAqXG4gKiAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJ2I2YjMxM2EzLWFiODQtNDc5Yy1iYWVhLTIwNmY2YmZmMzM3JyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKHsgZ3JvdXBJZDogJzAwYjUzMzA4LTk4MzMtNDdmMi1iMjFlLTEyNzhjMDdkNTNiOCcgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgYXBpRW5kcG9pbnQgPSAnbWVtYmVyL2xvY2FsJztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIHVzZXIgaWQuIERlZmF1bHRzIHRvIGEgYmxhbmsgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdXNlcklkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIGdyb3VwIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy4gTm90ZSB0aGF0IHRoaXMgaXMgdGhlIGdyb3VwICppZCosIG5vdCB0aGUgZ3JvdXAgKm5hbWUqLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXBJZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zLCBzZXJ2aWNlT3B0aW9ucyk7XG5cbiAgICB2YXIgZ2V0RmluYWxQYXJhbXMgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgIGlmICh0eXBlb2YgcGFyYW1zID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBwYXJhbXMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICB9O1xuXG4gICAgdmFyIHBhdGNoVXNlckFjdGl2ZUZpZWxkID0gZnVuY3Rpb24gKHBhcmFtcywgYWN0aXZlLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLCB7XG4gICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHBhcmFtcy5ncm91cElkICsgJy8nICsgcGFyYW1zLnVzZXJJZFxuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gaHR0cC5wYXRjaCh7IGFjdGl2ZTogYWN0aXZlIH0sIGh0dHBPcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGFsbCBvZiB0aGUgZ3JvdXAgbWVtYmVyc2hpcHMgZm9yIG9uZSBlbmQgdXNlci4gVGhlIG1lbWJlcnNoaXAgZGV0YWlscyBhcmUgcmV0dXJuZWQgaW4gYW4gYXJyYXksIHdpdGggb25lIGVsZW1lbnQgKGdyb3VwIHJlY29yZCkgZm9yIGVhY2ggZ3JvdXAgdG8gd2hpY2ggdGhlIGVuZCB1c2VyIGJlbG9uZ3MuXG4gICAgICAgICpcbiAgICAgICAgKiBJbiB0aGUgbWVtYmVyc2hpcCBhcnJheSwgZWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGlkLCBwcm9qZWN0IGlkLCBhY2NvdW50ICh0ZWFtKSBpZCwgYW5kIGFuIGFycmF5IG9mIG1lbWJlcnMuIEhvd2V2ZXIsIG9ubHkgdGhlIHVzZXIgd2hvc2UgdXNlcklkIGlzIGluY2x1ZGVkIGluIHRoZSBjYWxsIGlzIGxpc3RlZCBpbiB0aGUgbWVtYmVycyBhcnJheSAocmVnYXJkbGVzcyBvZiB3aGV0aGVyIHRoZXJlIGFyZSBvdGhlciBtZW1iZXJzIGluIHRoaXMgZ3JvdXApLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cHNGb3JVc2VyKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbihtZW1iZXJzaGlwcyl7XG4gICAgICAgICogICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7IGk8bWVtYmVyc2hpcHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhtZW1iZXJzaGlwc1tpXS5ncm91cElkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIH1cbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cHNGb3JVc2VyKHsgdXNlcklkOiAnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fSBgcGFyYW1zYCBUaGUgdXNlciBpZCBmb3IgdGhlIGVuZCB1c2VyLiBBbHRlcm5hdGl2ZWx5LCBhbiBvYmplY3Qgd2l0aCBmaWVsZCBgdXNlcklkYCBhbmQgdmFsdWUgdGhlIHVzZXIgaWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuXG4gICAgICAgIGdldEdyb3Vwc0ZvclVzZXI6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGlzU3RyaW5nID0gdHlwZW9mIHBhcmFtcyA9PT0gJ3N0cmluZyc7XG4gICAgICAgICAgICB2YXIgb2JqUGFyYW1zID0gZ2V0RmluYWxQYXJhbXMocGFyYW1zKTtcbiAgICAgICAgICAgIGlmICghaXNTdHJpbmcgJiYgIW9ialBhcmFtcy51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHVzZXJJZCBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBnZXRQYXJtcyA9IGlzU3RyaW5nID8geyB1c2VySWQ6IHBhcmFtcyB9IDogX3BpY2sob2JqUGFyYW1zLCAndXNlcklkJyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoZ2V0UGFybXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IG9uZSBncm91cCwgaW5jbHVkaW5nIGFuIGFycmF5IG9mIGFsbCBpdHMgbWVtYmVycy5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKCc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbihncm91cCl7XG4gICAgICAgICogICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7IGk8Z3JvdXAubWVtYmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICAqICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGdyb3VwLm1lbWJlcnNbaV0udXNlck5hbWUpO1xuICAgICAgICAqICAgICAgICAgICAgICAgfVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIG1hLmdldEdyb3VwRGV0YWlscyh7IGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ3xvYmplY3R9IGBwYXJhbXNgIFRoZSBncm91cCBpZC4gQWx0ZXJuYXRpdmVseSwgYW4gb2JqZWN0IHdpdGggZmllbGQgYGdyb3VwSWRgIGFuZCB2YWx1ZSB0aGUgZ3JvdXAgaWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBnZXRHcm91cERldGFpbHM6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgdmFyIGlzU3RyaW5nID0gdHlwZW9mIHBhcmFtcyA9PT0gJ3N0cmluZyc7XG4gICAgICAgICAgICB2YXIgb2JqUGFyYW1zID0gZ2V0RmluYWxQYXJhbXMocGFyYW1zKTtcbiAgICAgICAgICAgIGlmICghaXNTdHJpbmcgJiYgIW9ialBhcmFtcy5ncm91cElkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBncm91cElkIHNwZWNpZmllZC4nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGdyb3VwSWQgPSBpc1N0cmluZyA/IHBhcmFtcyA6IG9ialBhcmFtcy5ncm91cElkO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgZ3JvdXBJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoe30sIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBTZXQgYSBwYXJ0aWN1bGFyIGVuZCB1c2VyIGFzIGBhY3RpdmVgLiBBY3RpdmUgZW5kIHVzZXJzIGNhbiBiZSBhc3NpZ25lZCB0byBbd29ybGRzXSguLi93b3JsZC1tYW5hZ2VyLykgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZHVyaW5nIGF1dG9tYXRpYyBhc3NpZ25tZW50LlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5tYWtlVXNlckFjdGl2ZSh7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFRoZSBlbmQgdXNlciBhbmQgZ3JvdXAgaW5mb3JtYXRpb24uXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMudXNlcklkYCBUaGUgaWQgb2YgdGhlIGVuZCB1c2VyIHRvIG1ha2UgYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggdGhpcyBlbmQgdXNlciBiZWxvbmdzLCBhbmQgaW4gd2hpY2ggdGhlIGVuZCB1c2VyIHNob3VsZCBiZWNvbWUgYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgbWFrZVVzZXJBY3RpdmU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXRjaFVzZXJBY3RpdmVGaWVsZChwYXJhbXMsIHRydWUsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFNldCBhIHBhcnRpY3VsYXIgZW5kIHVzZXIgYXMgYGluYWN0aXZlYC4gSW5hY3RpdmUgZW5kIHVzZXJzIGFyZSBub3QgYXNzaWduZWQgdG8gW3dvcmxkc10oLi4vd29ybGQtbWFuYWdlci8pIGluIG11bHRpcGxheWVyIGdhbWVzIGR1cmluZyBhdXRvbWF0aWMgYXNzaWdubWVudC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEubWFrZVVzZXJJbmFjdGl2ZSh7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFRoZSBlbmQgdXNlciBhbmQgZ3JvdXAgaW5mb3JtYXRpb24uXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMudXNlcklkYCBUaGUgaWQgb2YgdGhlIGVuZCB1c2VyIHRvIG1ha2UgaW5hY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZ3JvdXBJZGAgVGhlIGlkIG9mIHRoZSBncm91cCB0byB3aGljaCB0aGlzIGVuZCB1c2VyIGJlbG9uZ3MsIGFuZCBpbiB3aGljaCB0aGUgZW5kIHVzZXIgc2hvdWxkIGJlY29tZSBpbmFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIG1ha2VVc2VySW5hY3RpdmU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXRjaFVzZXJBY3RpdmVGaWVsZChwYXJhbXMsIGZhbHNlLCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICpcbiAqICMjUnVuIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIFJ1biBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIHBlcmZvcm0gY29tbW9uIHRhc2tzIGFyb3VuZCBjcmVhdGluZyBhbmQgdXBkYXRpbmcgcnVucywgdmFyaWFibGVzLCBhbmQgZGF0YS5cbiAqXG4gKiBXaGVuIGJ1aWxkaW5nIGludGVyZmFjZXMgdG8gc2hvdyBydW4gb25lIGF0IGEgdGltZSAoYXMgZm9yIHN0YW5kYXJkIGVuZCB1c2VycyksIHR5cGljYWxseSB5b3UgZmlyc3QgaW5zdGFudGlhdGUgYSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgYW5kIHRoZW4gYWNjZXNzIHRoZSBSdW4gU2VydmljZSB0aGF0IGlzIGF1dG9tYXRpY2FsbHkgcGFydCBvZiB0aGUgbWFuYWdlciwgcmF0aGVyIHRoYW4gaW5zdGFudGlhdGluZyB0aGUgUnVuIFNlcnZpY2UgZGlyZWN0bHkuIFRoaXMgaXMgYmVjYXVzZSB0aGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGNvbnRyb2wgb3ZlciBydW4gY3JlYXRpb24gZGVwZW5kaW5nIG9uIHJ1biBzdGF0ZXMuXG4gKlxuICogSG93ZXZlciwgbWFueSBvZiB0aGUgRXBpY2VudGVyIHNhbXBsZSBwcm9qZWN0cyB1c2UgYSBSdW4gU2VydmljZSwgYmVjYXVzZSBnZW5lcmFsbHkgdGhlIHNhbXBsZSBwcm9qZWN0cyBhcmUgcGxheWVkIGluIG9uZSBlbmQgdXNlciBzZXNzaW9uIGFuZCBkb24ndCBjYXJlIGFib3V0IHJ1biBzdGF0ZXMgb3IgW3J1biBzdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pLiBUaGUgUnVuIEFQSSBTZXJ2aWNlIGlzIGFsc28gdXNlZnVsIGZvciBidWlsZGluZyBhbiBpbnRlcmZhY2UgZm9yIGEgZmFjaWxpdGF0b3IsIGJlY2F1c2UgaXQgbWFrZXMgaXQgZWFzeSB0byBsaXN0IGRhdGEgYWNyb3NzIG11bHRpcGxlIHJ1bnMgKHVzaW5nIHRoZSBgZmlsdGVyKClgIGFuZCBgcXVlcnkoKWAgbWV0aG9kcykuXG4gKlxuICogVG8gdXNlIHRoZSBSdW4gQVBJIFNlcnZpY2UsIGluc3RhbnRpYXRlIGl0IGJ5IHBhc3NpbmcgaW46XG4gKlxuICogKiBgYWNjb3VudGA6IEVwaWNlbnRlciBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cywgKipVc2VyIElEKiogZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiAqICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiAqXG4gKiBGb3IgZXhhbXBsZSxcbiAqXG4gKiAgICAgICB2YXIgcnMgPSBuZXcgRi5zZXJ2aWNlLlJ1bih7XG4gKiAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgfSk7XG4gKiAgICAgIHJzLmNyZWF0ZSgnc3VwcGx5X2NoYWluX2dhbWUucHknKS50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgfSk7XG4gKlxuICpcbiAqIEFkZGl0aW9uYWxseSwgYWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgUnVuIEFQSSBTZXJ2aWNlIGRlZmF1bHRzIGxpc3RlZCBiZWxvdy5cbiAqXG4gKiBOb3RlIHRoYXQgaW4gYWRkaXRpb24gdG8gdGhlIGBhY2NvdW50YCwgYHByb2plY3RgLCBhbmQgYG1vZGVsYCwgdGhlIFJ1biBTZXJ2aWNlIHBhcmFtZXRlcnMgb3B0aW9uYWxseSBpbmNsdWRlIGEgYHNlcnZlcmAgb2JqZWN0LCB3aG9zZSBgaG9zdGAgZmllbGQgY29udGFpbnMgdGhlIFVSSSBvZiB0aGUgRm9yaW8gc2VydmVyLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0LCBidXQgeW91IGNhbiBwYXNzIGl0IGV4cGxpY2l0bHkgaWYgZGVzaXJlZC4gSXQgaXMgbW9zdCBjb21tb25seSB1c2VkIGZvciBjbGFyaXR5IHdoZW4geW91IGFyZSBbaG9zdGluZyBhbiBFcGljZW50ZXIgcHJvamVjdCBvbiB5b3VyIG93biBzZXJ2ZXJdKC4uLy4uLy4uL2hvd190by9zZWxmX2hvc3RpbmcvKS5cbiAqXG4gKiAgICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5X2NoYWluX2dhbWUucHknLFxuICogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiAqICAgICAgICAgICB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIHJtLmdldFJ1bigpXG4gKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuKSB7XG4gKiAgICAgICAgICAgICAgIC8vIHRoZSBSdW5NYW5hZ2VyLnJ1biBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuICogICAgICAgICAgICAgICAvLyBzbyBhbnkgUnVuIFNlcnZpY2UgbWV0aG9kIGlzIHZhbGlkIGhlcmVcbiAqICAgICAgICAgICAgICAgdmFyIHJzID0gcm0ucnVuO1xuICogICAgICAgICAgICAgICBycy5kbygnc29tZU9wZXJhdGlvbicpO1xuICogICAgICAgfSlcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBydXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcnVuLXV0aWwnKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBWYXJpYWJsZXNTZXJ2aWNlID0gcmVxdWlyZSgnLi92YXJpYWJsZXMtYXBpLXNlcnZpY2UnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgLy8gY29uZmlnIHx8IChjb25maWcgPSBjb25maWdTZXJ2aWNlLmdldCgpKTtcbiAgICB2YXIgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkoeyBzeW5jaHJvbm91czogdHJ1ZSB9KTtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiBzdG9yZS5nZXQoJ2VwaWNlbnRlci5wcm9qZWN0LnRva2VuJykgfHwgc3RvcmUuZ2V0KCdlcGljZW50ZXIudG9rZW4nKSB8fCAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvamVjdDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyaXRlcmlhIGJ5IHdoaWNoIHRvIGZpbHRlciBydW5zLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBmaWx0ZXI6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZW5pZW5jZSBhbGlhcyBmb3IgZmlsdGVyLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgaWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGbGFnIGRldGVybWluZXMgaWYgYFgtQXV0b1Jlc3RvcmU6IHRydWVgIGhlYWRlciBpcyBzZW50IHRvIEVwaWNlbnRlci4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGF1dG9SZXN0b3JlOiB0cnVlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3AsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG5cbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmlkKSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmlkO1xuICAgIH1cblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHVybENvbmZpZy5maWx0ZXIgPSAnOyc7XG4gICAgdXJsQ29uZmlnLmdldEZpbHRlclVSTCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdydW4nKTtcbiAgICAgICAgdmFyIGZpbHRlciA9IHF1dGlsLnRvTWF0cml4Rm9ybWF0KHNlcnZpY2VPcHRpb25zLmZpbHRlcik7XG5cbiAgICAgICAgaWYgKGZpbHRlcikge1xuICAgICAgICAgICAgdXJsICs9IGZpbHRlciArICcvJztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsO1xuICAgIH07XG5cbiAgICB1cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgZmlsdGVyID0gc2VydmljZU9wdGlvbnMuZmlsdGVyO1xuICAgICAgICAvLyBUaGUgc2VtaWNvbG9uIHNlcGFyYXRlZCBmaWx0ZXIgaXMgdXNlZCB3aGVuIGZpbHRlciBpcyBhbiBvYmplY3RcbiAgICAgICAgdmFyIGlzRmlsdGVyUnVuSWQgPSBmaWx0ZXIgJiYgJC50eXBlKGZpbHRlcikgPT09ICdzdHJpbmcnO1xuICAgICAgICBpZiAoc2VydmljZU9wdGlvbnMuYXV0b1Jlc3RvcmUgJiYgaXNGaWx0ZXJSdW5JZCkge1xuICAgICAgICAgICAgLy8gQnkgZGVmYXVsdCBhdXRvcmVwbGF5IHRoZSBydW4gYnkgc2VuZGluZyB0aGlzIGhlYWRlciB0byBlcGljZW50ZXJcbiAgICAgICAgICAgIC8vIGh0dHBzOi8vZm9yaW8uY29tL2VwaWNlbnRlci9kb2NzL3B1YmxpYy9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI3JldHJpZXZpbmdcbiAgICAgICAgICAgIHZhciBhdXRvcmVzdG9yZU9wdHMgPSB7XG4gICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICAnWC1BdXRvUmVzdG9yZSc6IHRydWVcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIGF1dG9yZXN0b3JlT3B0cywgb3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gb3B0aW9ucztcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRGaWx0ZXJVUkxcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICBodHRwLnNwbGl0R2V0ID0gcnV0aWwuc3BsaXRHZXRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBzZXRGaWx0ZXJPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAob3B0aW9ucy5pZCkge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5pZDtcbiAgICAgICAgfVxuICAgICAgICBpZiAob3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuZmlsdGVyO1xuICAgICAgICB9XG4gICAgICAgIGlmICghc2VydmljZU9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGZpbHRlciBzcGVjaWZpZWQgdG8gYXBwbHkgb3BlcmF0aW9ucyBhZ2FpbnN0Jyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FzeW5jQVBJID0ge1xuICAgICAgICB1cmxDb25maWc6IHVybENvbmZpZyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JlYXRlIGEgbmV3IHJ1bi5cbiAgICAgICAgICpcbiAgICAgICAgICogTk9URTogVHlwaWNhbGx5IHRoaXMgaXMgbm90IHVzZWQhIFVzZSBgUnVuTWFuYWdlci5nZXRSdW4oKWAgd2l0aCBhIGBzdHJhdGVneWAgb2YgYGFsd2F5cy1uZXdgLCBvciB1c2UgYFJ1bk1hbmFnZXIucmVzZXQoKWAuIFNlZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgZm9yIG1vcmUgZGV0YWlscy5cbiAgICAgICAgICpcbiAgICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgcnMuY3JlYXRlKCdoZWxsb193b3JsZC5qbCcpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd8T2JqZWN0fSBgcGFyYW1zYCBJZiBhIHN0cmluZywgdGhlIG5hbWUgb2YgdGhlIHByaW1hcnkgW21vZGVsIGZpbGVdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pLiBUaGlzIGlzIHRoZSBvbmUgZmlsZSBpbiB0aGUgcHJvamVjdCB0aGF0IGV4cGxpY2l0bHkgZXhwb3NlcyB2YXJpYWJsZXMgYW5kIG1ldGhvZHMsIGFuZCBpdCBtdXN0IGJlIHN0b3JlZCBpbiB0aGUgTW9kZWwgZm9sZGVyIG9mIHlvdXIgRXBpY2VudGVyIHByb2plY3QuIElmIGFuIG9iamVjdCwgbWF5IGluY2x1ZGUgYG1vZGVsYCwgYHNjb3BlYCwgYW5kIGBmaWxlc2AuIChTZWUgdGhlIFtSdW4gTWFuYWdlcl0oLi4vcnVuX21hbmFnZXIvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBgc2NvcGVgIGFuZCBgZmlsZXNgLilcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdydW4nKSB9KTtcbiAgICAgICAgICAgIHZhciBydW5BcGlQYXJhbXMgPSBbJ21vZGVsJywgJ3Njb3BlJywgJ2ZpbGVzJ107XG4gICAgICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAvLyB0aGlzIGlzIGp1c3QgdGhlIG1vZGVsIG5hbWVcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSB7IG1vZGVsOiBwYXJhbXMgfTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zLCBydW5BcGlQYXJhbXMpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IGNyZWF0ZU9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgICAgIGNyZWF0ZU9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJlc3BvbnNlLmlkOyAvL2FsbCBmdXR1cmUgY2hhaW5lZCBjYWxscyB0byBvcGVyYXRlIG9uIHRoaXMgaWRcbiAgICAgICAgICAgICAgICByZXR1cm4gb2xkU3VjY2Vzcy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZXR1cm5zIHBhcnRpY3VsYXIgcnVucywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxc2Agb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiBUaGUgZWxlbWVudHMgb2YgdGhlIGBxc2Agb2JqZWN0IGFyZSBBTkRlZCB0b2dldGhlciB3aXRoaW4gYSBzaW5nbGUgY2FsbCB0byBgLnF1ZXJ5KClgLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJldHVybnMgcnVucyB3aXRoIHNhdmVkID0gdHJ1ZSBhbmQgdmFyaWFibGVzLnByaWNlID4gMSxcbiAgICAgICAgICogICAgICAvLyB3aGVyZSB2YXJpYWJsZXMucHJpY2UgaGFzIGJlZW4gcGVyc2lzdGVkIChyZWNvcmRlZClcbiAgICAgICAgICogICAgICAvLyBpbiB0aGUgbW9kZWwuXG4gICAgICAgICAqICAgICBycy5xdWVyeSh7XG4gICAgICAgICAqICAgICAgICAgICdzYXZlZCc6ICd0cnVlJyxcbiAgICAgICAgICogICAgICAgICAgJy5wcmljZSc6ICc+MSdcbiAgICAgICAgICogICAgICAgfSxcbiAgICAgICAgICogICAgICAge1xuICAgICAgICAgKiAgICAgICAgICBzdGFydHJlY29yZDogMixcbiAgICAgICAgICogICAgICAgICAgZW5kcmVjb3JkOiA1XG4gICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHFzYCBRdWVyeSBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIFF1ZXJ5aW5nIGZvciB2YXJpYWJsZXMgaXMgYXZhaWxhYmxlIGZvciBydW5zIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpIGFuZCBmb3IgcnVucyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBpZiB0aGUgdmFyaWFibGVzIGFyZSBwZXJzaXN0ZWQgKGUuZy4gdGhhdCBoYXZlIGJlZW4gYHJlY29yZGBlZCBpbiB5b3VyIEp1bGlhIG1vZGVsKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChxcywgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHFzOyAvL3Nob3VsZG4ndCBiZSBhYmxlIHRvIG92ZXItcmlkZVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuc3BsaXRHZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogU2ltaWxhciB0byBgLnF1ZXJ5KClgLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGZpbHRlcmAgRmlsdGVyIG9iamVjdC4gRWFjaCBrZXkgY2FuIGJlIGEgcHJvcGVydHkgb2YgdGhlIHJ1biBvciB0aGUgbmFtZSBvZiB2YXJpYWJsZSB0aGF0IGhhcyBiZWVuIHNhdmVkIGluIHRoZSBydW4gKHByZWZhY2VkIGJ5IGB2YXJpYWJsZXMuYCkuIEVhY2ggdmFsdWUgY2FuIGJlIGEgbGl0ZXJhbCB2YWx1ZSwgb3IgYSBjb21wYXJpc29uIG9wZXJhdG9yIGFuZCB2YWx1ZS4gKFNlZSBbbW9yZSBvbiBmaWx0ZXJpbmddKC4uLy4uLy4uL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaS8jZmlsdGVycykgYWxsb3dlZCBpbiB0aGUgdW5kZXJseWluZyBSdW4gQVBJLikgRmlsdGVyaW5nIGZvciB2YXJpYWJsZXMgaXMgYXZhaWxhYmxlIGZvciBydW5zIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpIGFuZCBmb3IgcnVucyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBpZiB0aGUgdmFyaWFibGVzIGFyZSBwZXJzaXN0ZWQgKGUuZy4gdGhhdCBoYXZlIGJlZW4gYHJlY29yZGBlZCBpbiB5b3VyIEp1bGlhIG1vZGVsKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiBmdW5jdGlvbiAoZmlsdGVyLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpKSB7XG4gICAgICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMuZmlsdGVyLCBmaWx0ZXIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBmaWx0ZXI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSB1cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuc3BsaXRHZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgcnVuLiBUaGlzIGluY2x1ZGVzIHN0YW5kYXJkIHJ1biBkYXRhIHN1Y2ggYXMgdGhlIGFjY291bnQsIG1vZGVsLCBwcm9qZWN0LCBhbmQgY3JlYXRlZCBhbmQgbGFzdCBtb2RpZmllZCBkYXRlcy4gVG8gcmVxdWVzdCBzcGVjaWZpYyBtb2RlbCB2YXJpYWJsZXMsIHBhc3MgdGhlbSBhcyBwYXJ0IG9mIHRoZSBgZmlsdGVyc2AgcGFyYW1ldGVyLlxuICAgICAgICAgKlxuICAgICAgICAgKiBOb3RlIHRoYXQgaWYgdGhlIHJ1biBpcyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSwgYW55IG1vZGVsIHZhcmlhYmxlcyBhcmUgYXZhaWxhYmxlOyBpZiB0aGUgcnVuIGlzIFtpbiB0aGUgZGF0YWJhc2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1kYiksIG9ubHkgbW9kZWwgdmFyaWFibGVzIHRoYXQgaGF2ZSBiZWVuIHBlcnNpc3RlZCAmbWRhc2g7IHRoYXQgaXMsIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCAmbWRhc2g7IGFyZSBhdmFpbGFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICBycy5sb2FkKCdiYjU4OTY3Ny1kNDc2LTQ5NzEtYTY4ZS0wYzU4ZDE5MWU0NTAnLCB7IGluY2x1ZGU6IFsnLnByaWNlJywgJy5zYWxlcyddIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHJ1bklEYCBUaGUgcnVuIGlkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGZpbHRlcnNgIChPcHRpb25hbCkgT2JqZWN0IGNvbnRhaW5pbmcgZmlsdGVycyBhbmQgb3BlcmF0aW9uIG1vZGlmaWVycy4gVXNlIGtleSBgaW5jbHVkZWAgdG8gbGlzdCBtb2RlbCB2YXJpYWJsZXMgdGhhdCB5b3Ugd2FudCB0byBpbmNsdWRlIGluIHRoZSByZXNwb25zZS4gT3RoZXIgYXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChydW5JRCwgZmlsdGVycywgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHJ1bklEKSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gcnVuSUQ7IC8vc2hvdWxkbid0IGJlIGFibGUgdG8gb3Zlci1yaWRlXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSB1cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGF0dHJpYnV0ZXMgKGRhdGEsIG1vZGVsIHZhcmlhYmxlcykgb2YgdGhlIHJ1bi5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyBhZGQgJ2NvbXBsZXRlZCcgZmllbGQgdG8gcnVuIHJlY29yZFxuICAgICAgICAgKiAgICAgcnMuc2F2ZSh7IGNvbXBsZXRlZDogdHJ1ZSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIC8vIHVwZGF0ZSAnc2F2ZWQnIGZpZWxkIG9mIHJ1biByZWNvcmQsIGFuZCB1cGRhdGUgdmFsdWVzIG9mIG1vZGVsIHZhcmlhYmxlcyBmb3IgdGhpcyBydW5cbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBzYXZlZDogdHJ1ZSwgdmFyaWFibGVzOiB7IGE6IDIzLCBiOiAyMyB9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGF0dHJpYnV0ZXNgIFRoZSBydW4gZGF0YSBhbmQgdmFyaWFibGVzIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgYXR0cmlidXRlcy52YXJpYWJsZXNgIE1vZGVsIHZhcmlhYmxlcyBtdXN0IGJlIGluY2x1ZGVkIGluIGEgYHZhcmlhYmxlc2AgZmllbGQgd2l0aGluIHRoZSBgYXR0cmlidXRlc2Agb2JqZWN0LiAoT3RoZXJ3aXNlIHRoZXkgYXJlIHRyZWF0ZWQgYXMgcnVuIGRhdGEgYW5kIGFkZGVkIHRvIHRoZSBydW4gcmVjb3JkIGRpcmVjdGx5LilcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGF0dHJpYnV0ZXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goYXR0cmlidXRlcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIGEgbWV0aG9kIGZyb20gdGhlIG1vZGVsLlxuICAgICAgICAgKlxuICAgICAgICAgKiBEZXBlbmRpbmcgb24gdGhlIGxhbmd1YWdlIGluIHdoaWNoIHlvdSBoYXZlIHdyaXR0ZW4geW91ciBtb2RlbCwgdGhlIG1ldGhvZCBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiBUaGUgYHBhcmFtc2AgYXJndW1lbnQgaXMgbm9ybWFsbHkgYW4gYXJyYXkgb2YgYXJndW1lbnRzIHRvIHRoZSBgb3BlcmF0aW9uYC4gSW4gdGhlIHNwZWNpYWwgY2FzZSB3aGVyZSBgb3BlcmF0aW9uYCBvbmx5IHRha2VzIG9uZSBhcmd1bWVudCwgeW91IGFyZSBub3QgcmVxdWlyZWQgdG8gcHV0IHRoYXQgYXJndW1lbnQgaW50byBhbiBhcnJheS5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IHlvdSBjYW4gY29tYmluZSB0aGUgYG9wZXJhdGlvbmAgYW5kIGBwYXJhbXNgIGFyZ3VtZW50cyBpbnRvIGEgc2luZ2xlIG9iamVjdCBpZiB5b3UgcHJlZmVyLCBhcyBpbiB0aGUgbGFzdCBleGFtcGxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJzb2x2ZVwiIHRha2VzIG5vIGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMuZG8oJ3NvbHZlJyk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgWydoZWxsbyddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJlY2hvXCIgdGFrZXMgb25lIGFyZ3VtZW50LCBhIHN0cmluZ1xuICAgICAgICAgKiAgICAgcnMuZG8oJ2VjaG8nLCAnaGVsbG8nKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJzdW1BcnJheVwiIHRha2VzIG9uZSBhcmd1bWVudCwgYW4gYXJyYXlcbiAgICAgICAgICogICAgIHJzLmRvKCdzdW1BcnJheScsIFtbNCwyLDFdXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiYWRkXCIgdGFrZXMgdHdvIGFyZ3VtZW50cywgYm90aCBpbnRlZ2Vyc1xuICAgICAgICAgKiAgICAgcnMuZG8oeyBuYW1lOidhZGQnLCBwYXJhbXM6WzIsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgb3BlcmF0aW9uYCBOYW1lIG9mIG1ldGhvZC5cbiAgICAgICAgICogQHBhcmFtIHtBcnJheX0gYHBhcmFtc2AgKE9wdGlvbmFsKSBBbnkgcGFyYW1ldGVycyB0aGUgb3BlcmF0aW9uIHRha2VzLCBwYXNzZWQgYXMgYW4gYXJyYXkuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXksIGFuZCBjYW4ganVzdCBwYXNzIGl0IGRpcmVjdGx5LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBkbzogZnVuY3Rpb24gKG9wZXJhdGlvbiwgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAvLyBjb25zb2xlLmxvZygnZG8nLCBvcGVyYXRpb24sIHBhcmFtcyk7XG4gICAgICAgICAgICB2YXIgb3BzQXJncztcbiAgICAgICAgICAgIHZhciBwb3N0T3B0aW9ucztcbiAgICAgICAgICAgIGlmIChvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3BzQXJncyA9IHBhcmFtcztcbiAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSkge1xuICAgICAgICAgICAgICAgICAgICBvcHNBcmdzID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgb3BzQXJncyA9IHBhcmFtcztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gcnV0aWwubm9ybWFsaXplT3BlcmF0aW9ucyhvcGVyYXRpb24sIG9wc0FyZ3MpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBwb3N0T3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHNldEZpbHRlck9yVGhyb3dFcnJvcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBwcm1zID0gKHJlc3VsdC5hcmdzWzBdLmxlbmd0aCAmJiAocmVzdWx0LmFyZ3NbMF0gIT09IG51bGwgJiYgcmVzdWx0LmFyZ3NbMF0gIT09IHVuZGVmaW5lZCkpID8gcmVzdWx0LmFyZ3NbMF0gOiBbXTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoeyBhcmd1bWVudHM6IHBybXMgfSwgJC5leHRlbmQodHJ1ZSwge30sIGh0dHBPcHRpb25zLCB7XG4gICAgICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMKCkgKyAnb3BlcmF0aW9ucy8nICsgcmVzdWx0Lm9wc1swXSArICcvJ1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbCwgc2VxdWVudGlhbGx5LlxuICAgICAgICAgKlxuICAgICAgICAgKiBEZXBlbmRpbmcgb24gdGhlIGxhbmd1YWdlIGluIHdoaWNoIHlvdSBoYXZlIHdyaXR0ZW4geW91ciBtb2RlbCwgdGhlIG1ldGhvZHMgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kcyBcImluaXRpYWxpemVcIiBhbmQgXCJzb2x2ZVwiIGRvIG5vdCB0YWtlIGFueSBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbJ2luaXRpYWxpemUnLCAnc29sdmUnXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kcyBcImluaXRcIiBhbmQgXCJyZXNldFwiIHRha2UgdHdvIGFyZ3VtZW50cyBlYWNoXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWyAgeyBuYW1lOiAnaW5pdCcsIHBhcmFtczogWzEsMl0gfSxcbiAgICAgICAgICogICAgICAgICAgICAgICAgICB7IG5hbWU6ICdyZXNldCcsIHBhcmFtczogWzIsM10gfV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImluaXRcIiB0YWtlcyB0d28gYXJndW1lbnRzLFxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcInJ1bm1vZGVsXCIgdGFrZXMgbm9uZVxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncnVubW9kZWwnLCBwYXJhbXM6IFtdIH1dKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtBcnJheX0gYG9wZXJhdGlvbnNgIElmIG5vbmUgb2YgdGhlIG1ldGhvZHMgdGFrZSBwYXJhbWV0ZXJzLCBwYXNzIGFuIGFycmF5IG9mIHRoZSBtZXRob2QgbmFtZXMgKHN0cmluZ3MpLiBJZiBhbnkgb2YgdGhlIG1ldGhvZHMgZG8gdGFrZSBwYXJhbWV0ZXJzLCBwYXNzIGFuIGFycmF5IG9mIG9iamVjdHMsIGVhY2ggb2Ygd2hpY2ggY29udGFpbnMgYSBtZXRob2QgbmFtZSBhbmQgaXRzIG93biAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNlcmlhbDogZnVuY3Rpb24gKG9wZXJhdGlvbnMsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIG9wUGFyYW1zID0gcnV0aWwubm9ybWFsaXplT3BlcmF0aW9ucyhvcGVyYXRpb25zLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wcyA9IG9wUGFyYW1zLm9wcztcbiAgICAgICAgICAgIHZhciBhcmdzID0gb3BQYXJhbXMuYXJncztcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBwb3N0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb1NpbmdsZU9wID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBvcCA9IG9wcy5zaGlmdCgpO1xuICAgICAgICAgICAgICAgIHZhciBhcmcgPSBhcmdzLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgICAgICBtZS5kbyhvcCwgYXJnLCB7XG4gICAgICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChvcHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2Vzcy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBlcnJvcjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVqZWN0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBkb1NpbmdsZU9wKCk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGwgc2V2ZXJhbCBtZXRob2RzIGZyb20gdGhlIG1vZGVsLCBleGVjdXRpbmcgdGhlbSBpbiBwYXJhbGxlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2RzIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kcyBcInNvbHZlXCIgYW5kIFwicmVzZXRcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5wYXJhbGxlbChbJ3NvbHZlJywgJ3Jlc2V0J10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJhZGRcIiBhbmQgXCJzdWJ0cmFjdFwiIHRha2UgdHdvIGFyZ3VtZW50cyBlYWNoXG4gICAgICAgICAqICAgICBycy5wYXJhbGxlbChbIHsgbmFtZTogJ2FkZCcsIHBhcmFtczogWzEsMl0gfSxcbiAgICAgICAgICogICAgICAgICAgICAgICAgICAgeyBuYW1lOiAnc3VidHJhY3QnLCBwYXJhbXM6WzIsM10gfV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJhZGRcIiBhbmQgXCJzdWJ0cmFjdFwiIHRha2UgdHdvIGFyZ3VtZW50cyBlYWNoXG4gICAgICAgICAqICAgICBycy5wYXJhbGxlbCh7IGFkZDogWzEsMl0sIHN1YnRyYWN0OiBbMiw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R9IGBvcGVyYXRpb25zYCBJZiBub25lIG9mIHRoZSBtZXRob2RzIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgbWV0aG9kIG5hbWVzIChhcyBzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBtZXRob2RzIGRvIHRha2UgcGFyYW1ldGVycywgeW91IGhhdmUgdHdvIG9wdGlvbnMuIFlvdSBjYW4gcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGEgbWV0aG9kIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLiBBbHRlcm5hdGl2ZWx5LCB5b3UgY2FuIHBhc3MgYSBzaW5nbGUgb2JqZWN0IHdpdGggdGhlIG1ldGhvZCBuYW1lIGFuZCBhIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy5cbiAgICAgICAgICogQHBhcmFtIHsqfSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHBhc3MgdG8gb3BlcmF0aW9ucy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcGFyYWxsZWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICAgICAgdmFyIG9wUGFyYW1zID0gcnV0aWwubm9ybWFsaXplT3BlcmF0aW9ucyhvcGVyYXRpb25zLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wcyA9IG9wUGFyYW1zLm9wcztcbiAgICAgICAgICAgIHZhciBhcmdzID0gb3BQYXJhbXMuYXJncztcbiAgICAgICAgICAgIHZhciBwb3N0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBxdWV1ZSAgPSBbXTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpPCBvcHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBxdWV1ZS5wdXNoKFxuICAgICAgICAgICAgICAgICAgICB0aGlzLmRvKG9wc1tpXSwgYXJnc1tpXSlcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJC53aGVuLmFwcGx5KHRoaXMsIHF1ZXVlKVxuICAgICAgICAgICAgICAgIC5kb25lKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5zdWNjZXNzLmFwcGx5KHRoaXMuYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVqZWN0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLmVycm9yLmFwcGx5KHRoaXMuYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljU3luY0FQSSA9IHtcbiAgICAgICAgZ2V0Q3VycmVudENvbmZpZzogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zO1xuICAgICAgICB9LFxuICAgICAgICAvKipcbiAgICAgICAgICAqIFJldHVybnMgYSBWYXJpYWJsZXMgU2VydmljZSBpbnN0YW5jZS4gVXNlIHRoZSB2YXJpYWJsZXMgaW5zdGFuY2UgdG8gbG9hZCwgc2F2ZSwgYW5kIHF1ZXJ5IGZvciBzcGVjaWZpYyBtb2RlbCB2YXJpYWJsZXMuIFNlZSB0aGUgW1ZhcmlhYmxlIEFQSSBTZXJ2aWNlXSguLi92YXJpYWJsZXMtYXBpLXNlcnZpY2UvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi5cbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgICpcbiAgICAgICAgICAqICAgICAgdmFyIHZzID0gcnMudmFyaWFibGVzKCk7XG4gICAgICAgICAgKiAgICAgIHZzLnNhdmUoeyBzYW1wbGVfaW50OiA0IH0pO1xuICAgICAgICAgICpcbiAgICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGNvbmZpZ2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICAqL1xuICAgICAgICB2YXJpYWJsZXM6IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAgICAgICAgIHZhciB2cyA9IG5ldyBWYXJpYWJsZXNTZXJ2aWNlKCQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgY29uZmlnLCB7XG4gICAgICAgICAgICAgICAgcnVuU2VydmljZTogdGhpc1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgICAgcmV0dXJuIHZzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FzeW5jQVBJKTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNTeW5jQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG4vKipcbiAqICMjU3RhdGUgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgU3RhdGUgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byByZXBsYXkgb3IgY2xvbmUgcnVucy4gSXQgYnJpbmdzIGV4aXN0aW5nLCBwZXJzaXN0ZWQgcnVuIGRhdGEgZnJvbSB0aGUgZGF0YWJhc2UgYmFjayBpbnRvIG1lbW9yeSwgdXNpbmcgdGhlIHNhbWUgcnVuIGlkIChgcmVwbGF5YCkgb3IgYSBuZXcgcnVuIGlkIChgY2xvbmVgKS4gUnVucyBtdXN0IGJlIGluIG1lbW9yeSBpbiBvcmRlciBmb3IgeW91IHRvIHVwZGF0ZSB2YXJpYWJsZXMgb3IgY2FsbCBvcGVyYXRpb25zIG9uIHRoZW0uXG4gKlxuICogU3BlY2lmaWNhbGx5LCB0aGUgU3RhdGUgQVBJIEFkYXB0ZXIgd29ya3MgYnkgXCJyZS1ydW5uaW5nXCIgdGhlIHJ1biAodXNlciBpbnRlcmFjdGlvbnMpIGZyb20gdGhlIGNyZWF0aW9uIG9mIHRoZSBydW4gdXAgdG8gdGhlIHRpbWUgaXQgd2FzIGxhc3QgcGVyc2lzdGVkIGluIHRoZSBkYXRhYmFzZS4gVGhpcyBwcm9jZXNzIHVzZXMgdGhlIGN1cnJlbnQgdmVyc2lvbiBvZiB0aGUgcnVuJ3MgbW9kZWwuIFRoZXJlZm9yZSwgaWYgdGhlIG1vZGVsIGhhcyBjaGFuZ2VkIHNpbmNlIHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQsIHRoZSByZXRyaWV2ZWQgcnVuIHdpbGwgdXNlIHRoZSBuZXcgbW9kZWwg4oCUIGFuZCBtYXkgZW5kIHVwIGhhdmluZyBkaWZmZXJlbnQgdmFsdWVzIG9yIGJlaGF2aW9yIGFzIGEgcmVzdWx0LiBVc2Ugd2l0aCBjYXJlIVxuICpcbiAqIFRvIHVzZSB0aGUgU3RhdGUgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHM6XG4gKlxuICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gKiAgICAgIHNhLnJlcGxheSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnfSk7XG4gKlxuICogVGhlIGNvbnN0cnVjdG9yIHRha2VzIGFuIG9wdGlvbmFsIGBvcHRpb25zYCBwYXJhbWV0ZXIgaW4gd2hpY2ggeW91IGNhbiBzcGVjaWZ5IHRoZSBgYWNjb3VudGAgYW5kIGBwcm9qZWN0YCBpZiB0aGV5IGFyZSBub3QgYWxyZWFkeSBhdmFpbGFibGUgaW4gdGhlIGN1cnJlbnQgY29udGV4dC5cbiAqXG4gKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGFwaUVuZHBvaW50ID0gJ21vZGVsL3N0YXRlJztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG5cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuICAgIHZhciBwYXJzZVJ1bklkT3JFcnJvciA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChwYXJhbXMpICYmIHBhcmFtcy5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHBhcmFtcy5ydW5JZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHBhc3MgaW4gYSBydW4gaWQnKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgKiBSZXBsYXkgYSBydW4uIEFmdGVyIHRoaXMgY2FsbCwgdGhlIHJ1biwgd2l0aCBpdHMgb3JpZ2luYWwgcnVuIGlkLCBpcyBub3cgYXZhaWxhYmxlIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoSXQgY29udGludWVzIHRvIGJlIHBlcnNpc3RlZCBpbnRvIHRoZSBFcGljZW50ZXIgZGF0YWJhc2UgYXQgcmVndWxhciBpbnRlcnZhbHMuKVxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciBzYSA9IG5ldyBGLnNlcnZpY2UuU3RhdGUoKTtcbiAgICAgICAgKiAgICAgIHNhLnJlcGxheSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyBvYmplY3QuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMucnVuSWRgIFRoZSBpZCBvZiB0aGUgcnVuIHRvIGJyaW5nIGJhY2sgdG8gbWVtb3J5LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnN0b3BCZWZvcmVgIChPcHRpb25hbCkgVGhlIHJ1biBpcyBhZHZhbmNlZCBvbmx5IHVwIHRvIHRoZSBmaXJzdCBvY2N1cnJlbmNlIG9mIHRoaXMgbWV0aG9kLlxuICAgICAgICAqIEBwYXJhbSB7YXJyYXl9IGBwYXJhbXMuZXhjbHVkZWAgKE9wdGlvbmFsKSBBcnJheSBvZiBtZXRob2RzIHRvIGV4Y2x1ZGUgd2hlbiBhZHZhbmNpbmcgdGhlIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIHJlcGxheTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHJ1bklkID0gcGFyc2VSdW5JZE9yRXJyb3IocGFyYW1zKTtcblxuICAgICAgICAgICAgdmFyIHJlcGxheU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBydW5JZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBwYXJhbXMgPSAkLmV4dGVuZCh0cnVlLCB7IGFjdGlvbjogJ3JlcGxheScgfSwgX3BpY2socGFyYW1zLCBbJ3N0b3BCZWZvcmUnLCAnZXhjbHVkZSddKSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCByZXBsYXlPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBDbG9uZSBhIGdpdmVuIHJ1biBhbmQgcmV0dXJuIGEgbmV3IHJ1biBpbiB0aGUgc2FtZSBzdGF0ZSBhcyB0aGUgZ2l2ZW4gcnVuLlxuICAgICAgICAqXG4gICAgICAgICogVGhlIG5ldyBydW4gaWQgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gVGhlIG5ldyBydW4gaW5jbHVkZXMgYSBjb3B5IG9mIGFsbCBvZiB0aGUgZGF0YSBmcm9tIHRoZSBvcmlnaW5hbCBydW4sIEVYQ0VQVDpcbiAgICAgICAgKlxuICAgICAgICAqICogVGhlIGBzYXZlZGAgZmllbGQgaW4gdGhlIG5ldyBydW4gcmVjb3JkIGlzIG5vdCBjb3BpZWQgZnJvbSB0aGUgb3JpZ2luYWwgcnVuIHJlY29yZC4gSXQgZGVmYXVsdHMgdG8gYGZhbHNlYC5cbiAgICAgICAgKiAqIFRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAgYnV0IG1heSBjaGFuZ2UgdG8gYHRydWVgIGFzIHRoZSBuZXcgcnVuIGlzIGFkdmFuY2VkLiBGb3IgZXhhbXBsZSwgaWYgdGhlcmUgaGFzIGJlZW4gYSBjYWxsIHRvIHRoZSBgc3RlcGAgZnVuY3Rpb24gKGZvciBWZW5zaW0gbW9kZWxzKSwgdGhlIGBpbml0aWFsaXplZGAgZmllbGQgaXMgc2V0IHRvIGB0cnVlYC5cbiAgICAgICAgKiAqIFRoZSBgY3JlYXRlZGAgZmllbGQgaW4gdGhlIG5ldyBydW4gcmVjb3JkIGlzIHRoZSBkYXRlIGFuZCB0aW1lIGF0IHdoaWNoIHRoZSBjbG9uZSB3YXMgY3JlYXRlZCAobm90IHRoZSB0aW1lIHRoYXQgdGhlIG9yaWdpbmFsIHJ1biB3YXMgY3JlYXRlZC4pXG4gICAgICAgICpcbiAgICAgICAgKiBUaGUgb3JpZ2luYWwgcnVuIHJlbWFpbnMgb25seSBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciBzYSA9IG5ldyBGLnNlcnZpY2UuU3RhdGUoKTtcbiAgICAgICAgKiAgICAgIHNhLmNsb25lKHtydW5JZDogJzE4NDJiYjVjLTgzYWQtNGJhOC1hOTU1LWJkMTNjYzJmZGI0ZicsIHN0b3BCZWZvcmU6ICdjYWxjdWxhdGVTY29yZScsIGV4Y2x1ZGU6IFsnaW50ZXJpbUNhbGN1bGF0aW9uJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyBvYmplY3QuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMucnVuSWRgIFRoZSBpZCBvZiB0aGUgcnVuIHRvIGNsb25lIGZyb20gbWVtb3J5LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnN0b3BCZWZvcmVgIChPcHRpb25hbCkgVGhlIG5ld2x5IGNsb25lZCBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBgcGFyYW1zLmV4Y2x1ZGVgIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBuZXdseSBjbG9uZWQgcnVuLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgY2xvbmU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdjbG9uZScgfSwgX3BpY2socGFyYW1zLCBbJ3N0b3BCZWZvcmUnLCAnZXhjbHVkZSddKSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCByZXBsYXlPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVwaVZlcnNpb24gPSByZXF1aXJlKCcuLi9hcGktdmVyc2lvbi5qc29uJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vVE9ETzogdXJsdXRpbHMgdG8gZ2V0IGhvc3QsIHNpbmNlIG5vIHdpbmRvdyBvbiBub2RlXG5cbiAgICB2YXIgQVBJX1BST1RPQ09MID0gJ2h0dHBzJztcbiAgICB2YXIgSE9TVF9BUElfTUFQUElORyA9IHtcbiAgICAgICAgJ2ZvcmlvLmNvbSc6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgJ2ZvcmlvZGV2LmNvbSc6ICdhcGkuZXBpY2VudGVyLmZvcmlvZGV2LmNvbSdcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0V4cG9ydHMgPSB7XG4gICAgICAgIHByb3RvY29sOiBBUElfUFJPVE9DT0wsXG5cbiAgICAgICAgYXBpOiAnJyxcblxuICAgICAgICBob3N0OiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGhvc3QgPSB3aW5kb3cubG9jYXRpb24uaG9zdDtcbiAgICAgICAgICAgIGlmICghaG9zdCB8fCBob3N0LmluZGV4T2YoJ2xvY2FsJykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgaG9zdCA9ICdmb3Jpby5jb20nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIChIT1NUX0FQSV9NQVBQSU5HW2hvc3RdKSA/IEhPU1RfQVBJX01BUFBJTkdbaG9zdF0gOiAnYXBpLicgKyBob3N0O1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFwcFBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG5cbiAgICAgICAgICAgIHJldHVybiBwYXRoICYmIHBhdGhbMV0gfHwgJyc7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgYWNjb3VudFBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYWNjbnQgPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIGlmIChwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnKSB7XG4gICAgICAgICAgICAgICAgYWNjbnQgPSBwYXRoWzJdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFjY250O1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIHByb2plY3RQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHByaiA9ICcnO1xuICAgICAgICAgICAgdmFyIHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuICAgICAgICAgICAgaWYgKHBhdGggJiYgcGF0aFsxXSA9PT0gJ2FwcCcpIHtcbiAgICAgICAgICAgICAgICBwcmogPSBwYXRoWzNdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHByajtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICB2ZXJzaW9uUGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciB2ZXJzaW9uID0gZXBpVmVyc2lvbi52ZXJzaW9uID8gZXBpVmVyc2lvbi52ZXJzaW9uICsgJy8nIDogJyc7XG4gICAgICAgICAgICByZXR1cm4gdmVyc2lvbjtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBpc0xvY2FsaG9zdDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGhvc3QgPSB3aW5kb3cubG9jYXRpb24uaG9zdDtcbiAgICAgICAgICAgIHJldHVybiAoIWhvc3QgfHwgaG9zdC5pbmRleE9mKCdsb2NhbCcpICE9PSAtMSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgZ2V0QVBJUGF0aDogZnVuY3Rpb24gKGFwaSkge1xuICAgICAgICAgICAgdmFyIFBST0pFQ1RfQVBJUyA9IFsncnVuJywgJ2RhdGEnLCAnZmlsZSddO1xuXG4gICAgICAgICAgICB2YXIgYXBpUGF0aCA9IHRoaXMucHJvdG9jb2wgKyAnOi8vJyArIHRoaXMuaG9zdCArICcvJyArIHRoaXMudmVyc2lvblBhdGggKyBhcGkgKyAnLyc7XG5cbiAgICAgICAgICAgIGlmICgkLmluQXJyYXkoYXBpLCBQUk9KRUNUX0FQSVMpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGFwaVBhdGggKz0gdGhpcy5hY2NvdW50UGF0aCArICcvJyArIHRoaXMucHJvamVjdFBhdGggICsgJy8nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFwaVBhdGg7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQocHVibGljRXhwb3J0cywgY29uZmlnKTtcbiAgICByZXR1cm4gcHVibGljRXhwb3J0cztcbn07XG4iLCIndXNlIHN0cmljdCc7XG4vKipcbiogIyNVc2VyIEFQSSBBZGFwdGVyXG4qXG4qIFRoZSBVc2VyIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gcmV0cmlldmUgZGV0YWlscyBhYm91dCBlbmQgdXNlcnMgaW4geW91ciB0ZWFtIChhY2NvdW50KS4gSXQgaXMgYmFzZWQgb24gdGhlIHF1ZXJ5aW5nIGNhcGFiaWxpdGllcyBvZiB0aGUgdW5kZXJseWluZyBSRVNUZnVsIFtVc2VyIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL3VzZXJfbWFuYWdlbWVudC91c2VyLykuXG4qXG4qIFRvIHVzZSB0aGUgVXNlciBBUEkgQWRhcHRlciwgaW5zdGFudGlhdGUgaXQgYW5kIHRoZW4gY2FsbCBpdHMgbWV0aG9kcy5cbipcbiogICAgICAgdmFyIHVhID0gbmV3IEYuc2VydmljZS5Vc2VyKHtcbiogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiogICAgICAgfSk7XG4qICAgICAgIHVhLmdldEJ5SWQoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpO1xuKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4qICAgICAgIHVhLmdldCh7IGlkOiBbJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycsXG4qICAgICAgICAgICAgICAgICAgICc0ZWE3NTYzMS00YzhkLTQ4NzItOWQ4MC1iNDYwMDE0NjQ3OGUnXSB9KTtcbipcbiogVGhlIGNvbnN0cnVjdG9yIHRha2VzIGFuIG9wdGlvbmFsIGBvcHRpb25zYCBwYXJhbWV0ZXIgaW4gd2hpY2ggeW91IGNhbiBzcGVjaWZ5IHRoZSBgYWNjb3VudGAgYW5kIGB0b2tlbmAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4qL1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY2VzcyB0b2tlbiB0byB1c2Ugd2hlbiBzZWFyY2hpbmcgZm9yIGVuZCB1c2Vycy4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICB0b2tlbjogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG5cbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCd1c2VyJylcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBwYXJ0aWN1bGFyIGVuZCB1c2VycyBpbiB5b3VyIHRlYW0sIGJhc2VkIG9uIHVzZXIgbmFtZSBvciB1c2VyIGlkLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqICAgICAgIHVhLmdldCh7IHVzZXJOYW1lOiAnanNtaXRoJyB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICc0ZWE3NTYzMS00YzhkLTQ4NzItOWQ4MC1iNDYwMDE0NjQ3OGUnXSB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBmaWx0ZXJgIE9iamVjdCB3aXRoIGZpZWxkIGB1c2VyTmFtZWAgYW5kIHZhbHVlIG9mIHRoZSB1c2VybmFtZS4gQWx0ZXJuYXRpdmVseSwgb2JqZWN0IHdpdGggZmllbGQgYGlkYCBhbmQgdmFsdWUgb2YgYW4gYXJyYXkgb2YgdXNlciBpZHMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuXG4gICAgICAgIGdldDogZnVuY3Rpb24gKGZpbHRlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBmaWx0ZXIgPSBmaWx0ZXIgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9uc1xuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIHRvUUZpbHRlciA9IGZ1bmN0aW9uIChmaWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzID0ge307XG5cbiAgICAgICAgICAgICAgICAvLyBBUEkgb25seSBzdXBwb3J0cyBmaWx0ZXJpbmcgYnkgdXNlcm5hbWUgZm9yIG5vd1xuICAgICAgICAgICAgICAgIGlmIChmaWx0ZXIudXNlck5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzLnEgPSBmaWx0ZXIudXNlck5hbWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciB0b0lkRmlsdGVycyA9IGZ1bmN0aW9uIChpZCkge1xuICAgICAgICAgICAgICAgIGlmICghaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlkID0gJC5pc0FycmF5KGlkKSA/IGlkIDogW2lkXTtcbiAgICAgICAgICAgICAgICByZXR1cm4gJ2lkPScgKyBpZC5qb2luKCcmaWQ9Jyk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0RmlsdGVycyA9IFtcbiAgICAgICAgICAgICAgICAnYWNjb3VudD0nICsgZ2V0T3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgIHRvSWRGaWx0ZXJzKGZpbHRlci5pZCksXG4gICAgICAgICAgICAgICAgcXV0aWwudG9RdWVyeUZvcm1hdCh0b1FGaWx0ZXIoZmlsdGVyKSlcbiAgICAgICAgICAgIF0uam9pbignJicpO1xuXG4gICAgICAgICAgICAvLyBzcGVjaWFsIGNhc2UgZm9yIHF1ZXJpZXMgd2l0aCBsYXJnZSBudW1iZXIgb2YgaWRzXG4gICAgICAgICAgICAvLyBtYWtlIGl0IGFzIGEgcG9zdCB3aXRoIEdFVCBzZW1hbnRpY3NcbiAgICAgICAgICAgIHZhciB0aHJlc2hvbGQgPSAzMDtcbiAgICAgICAgICAgIGlmIChmaWx0ZXIuaWQgJiYgJC5pc0FycmF5KGZpbHRlci5pZCkgJiYgZmlsdGVyLmlkLmxlbmd0aCA+PSB0aHJlc2hvbGQpIHtcbiAgICAgICAgICAgICAgICBnZXRPcHRpb25zLnVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCd1c2VyJykgKyAnP19tZXRob2Q9R0VUJztcbiAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgaWQ6IGZpbHRlci5pZCB9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldEZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgYSBzaW5nbGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIGlkLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqICAgICAgIHVhLmdldEJ5SWQoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJJZGAgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlciBpbiB5b3VyIHRlYW0uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuXG4gICAgICAgIGdldEJ5SWQ6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBwdWJsaWNBUEkuZ2V0KHsgaWQ6IHVzZXJJZCB9LCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcblxuXG5cblxuIiwiLyoqXG4gKlxuICogIyNWYXJpYWJsZXMgQVBJIFNlcnZpY2VcbiAqXG4gKiBVc2VkIGluIGNvbmp1bmN0aW9uIHdpdGggdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pIHRvIHJlYWQsIHdyaXRlLCBhbmQgc2VhcmNoIGZvciBzcGVjaWZpYyBtb2RlbCB2YXJpYWJsZXMuXG4gKlxuICogICAgIHZhciBybSA9IG5ldyBGLm1hbmFnZXIuUnVuTWFuYWdlcih7XG4gKiAgICAgICAgICAgcnVuOiB7XG4gKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgICAgICAgbW9kZWw6ICdzdXBwbHktY2hhaW4tbW9kZWwuamwnXG4gKiAgICAgICAgICAgfVxuICogICAgICB9KTtcbiAqICAgICBybS5nZXRSdW4oKVxuICogICAgICAgLnRoZW4oZnVuY3Rpb24oKSB7XG4gKiAgICAgICAgICB2YXIgdnMgPSBybS5ydW4udmFyaWFibGVzKCk7XG4gKiAgICAgICAgICB2cy5zYXZlKHtzYW1wbGVfaW50OiA0fSk7XG4gKiAgICAgICAgfSk7XG4gKlxuICovXG5cblxuICd1c2Ugc3RyaWN0JztcblxuIHZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbiB2YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBydW5zIG9iamVjdCB0byB3aGljaCB0aGUgdmFyaWFibGUgZmlsdGVycyBhcHBseS4gRGVmYXVsdHMgdG8gbnVsbC5cbiAgICAgICAgICogQHR5cGUge3J1blNlcnZpY2V9XG4gICAgICAgICAqL1xuICAgICAgICBydW5TZXJ2aWNlOiBudWxsXG4gICAgfTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG5cbiAgICB2YXIgZ2V0VVJMID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuZ2V0RmlsdGVyVVJMKCkgKyAndmFyaWFibGVzLyc7XG4gICAgfTtcblxuICAgIHZhciBhZGRBdXRvUmVzdG9yZUhlYWRlciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucy5ydW5TZXJ2aWNlLnVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihvcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0ge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH07XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIGh0dHBPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuICAgIGh0dHAuc3BsaXRHZXQgPSBydXRpbC5zcGxpdEdldEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHZhbHVlcyBmb3IgYSB2YXJpYWJsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICB2cy5sb2FkKCdzYW1wbGVfaW50JylcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKXtcbiAgICAgICAgICogICAgICAgICAgICAgIC8vIHZhbCBjb250YWlucyB0aGUgdmFsdWUgb2Ygc2FtcGxlX2ludFxuICAgICAgICAgKiAgICAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGB2YXJpYWJsZWAgTmFtZSBvZiB2YXJpYWJsZSB0byBsb2FkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAodmFyaWFibGUsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSBhZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsICQuZXh0ZW5kKHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogZ2V0VVJMKCkgKyB2YXJpYWJsZSArICcvJ1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZXR1cm5zIHBhcnRpY3VsYXIgdmFyaWFibGVzLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHF1ZXJ5YCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoWydwcmljZScsICdzYWxlcyddKVxuICAgICAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbih2YWwpIHtcbiAgICAgICAgICogICAgICAgICAgICAgIC8vIHZhbCBpcyBhbiBvYmplY3Qgd2l0aCB0aGUgdmFsdWVzIG9mIHRoZSByZXF1ZXN0ZWQgdmFyaWFibGVzOiB2YWwucHJpY2UsIHZhbC5zYWxlc1xuICAgICAgICAgKiAgICAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICB2cy5xdWVyeSh7IGluY2x1ZGU6WydwcmljZScsICdzYWxlcyddIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdHxBcnJheX0gYHF1ZXJ5YCBUaGUgbmFtZXMgb2YgdGhlIHZhcmlhYmxlcyByZXF1ZXN0ZWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICpcbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXVlcnksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAvL1F1ZXJ5IGFuZCBvdXRwdXRNb2RpZmllciBhcmUgYm90aCBxdWVyeXN0cmluZ3MgaW4gdGhlIHVybDsgb25seSBjYWxsaW5nIHRoZW0gb3V0IHNlcGFyYXRlbHkgaGVyZSB0byBiZSBjb25zaXN0ZW50IHdpdGggdGhlIG90aGVyIGNhbGxzXG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSBhZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIGlmICgkLmlzQXJyYXkocXVlcnkpKSB7XG4gICAgICAgICAgICAgICAgcXVlcnkgPSB7IGluY2x1ZGU6IHF1ZXJ5IH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAkLmV4dGVuZChxdWVyeSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuc3BsaXRHZXQocXVlcnksIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSB2YWx1ZXMgdG8gbW9kZWwgdmFyaWFibGVzLiBPdmVyd3JpdGVzIGV4aXN0aW5nIHZhbHVlcy4gTm90ZSB0aGF0IHlvdSBjYW4gb25seSB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlmIHRoZSBydW4gaXMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIChBbiBhbHRlcm5hdGUgd2F5IHRvIHVwZGF0ZSBtb2RlbCB2YXJpYWJsZXMgaXMgdG8gY2FsbCBhIG1ldGhvZCBmcm9tIHRoZSBtb2RlbCBhbmQgbWFrZSBzdXJlIHRoYXQgdGhlIG1ldGhvZCBwZXJzaXN0cyB0aGUgdmFyaWFibGVzLiBTZWUgYGRvYCwgYHNlcmlhbGAsIGFuZCBgcGFyYWxsZWxgIGluIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBmb3IgY2FsbGluZyBtZXRob2RzIGZyb20gdGhlIG1vZGVsLilcbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICB2cy5zYXZlKCdwcmljZScsIDQpO1xuICAgICAgICAgKiAgICAgIHZzLnNhdmUoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdHxTdHJpbmd9IGB2YXJpYWJsZWAgQW4gb2JqZWN0IGNvbXBvc2VkIG9mIHRoZSBtb2RlbCB2YXJpYWJsZXMgYW5kIHRoZSB2YWx1ZXMgdG8gc2F2ZS4gQWx0ZXJuYXRpdmVseSwgYSBzdHJpbmcgd2l0aCB0aGUgbmFtZSBvZiB0aGUgdmFyaWFibGUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgdmFsYCAoT3B0aW9uYWwpIElmIHBhc3NpbmcgYSBzdHJpbmcgZm9yIGB2YXJpYWJsZWAsIHVzZSB0aGlzIGFyZ3VtZW50IGZvciB0aGUgdmFsdWUgdG8gc2F2ZS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgYXR0cnMgPSB2YXJpYWJsZTtcbiAgICAgICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gTm90IEF2YWlsYWJsZSB1bnRpbCB1bmRlcmx5aW5nIEFQSSBzdXBwb3J0cyBQVVQuIE90aGVyd2lzZSBzYXZlIHdvdWxkIGJlIFBVVCBhbmQgbWVyZ2Ugd291bGQgYmUgUEFUQ0hcbiAgICAgICAgLy8gKlxuICAgICAgICAvLyAgKiBTYXZlIHZhbHVlcyB0byB0aGUgYXBpLiBNZXJnZXMgYXJyYXlzLCBidXQgb3RoZXJ3aXNlIHNhbWUgYXMgc2F2ZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdHxTdHJpbmd9IHZhcmlhYmxlIE9iamVjdCB3aXRoIGF0dHJpYnV0ZXMsIG9yIHN0cmluZyBrZXlcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R9IHZhbCBPcHRpb25hbCBpZiBwcmV2IHBhcmFtZXRlciB3YXMgYSBzdHJpbmcsIHNldCB2YWx1ZSBoZXJlXG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBleGFtcGxlXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSh7IHByaWNlOiA0LCBxdWFudGl0eTogNSwgcHJvZHVjdHM6IFsyLDMsNF0gfSlcbiAgICAgICAgLy8gICogICAgIHZzLm1lcmdlKCdwcmljZScsIDQpO1xuXG4gICAgICAgIC8vIG1lcmdlOiBmdW5jdGlvbiAodmFyaWFibGUsIHZhbCwgb3B0aW9ucykge1xuICAgICAgICAvLyAgICAgdmFyIGF0dHJzO1xuICAgICAgICAvLyAgICAgaWYgKHR5cGVvZiB2YXJpYWJsZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgLy8gICAgICAgYXR0cnMgPSB2YXJpYWJsZTtcbiAgICAgICAgLy8gICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgLy8gICAgIH0gZWxzZSB7XG4gICAgICAgIC8vICAgICAgIChhdHRycyA9IHt9KVt2YXJpYWJsZV0gPSB2YWw7XG4gICAgICAgIC8vICAgICB9XG4gICAgICAgIC8vICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIC8vICAgICByZXR1cm4gaHR0cC5wYXRjaC5jYWxsKHRoaXMsIGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIC8vIH1cbiAgICB9O1xuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiAjI1dvcmxkIEFQSSBBZGFwdGVyXG4gKlxuICogQSBbcnVuXSguLi8uLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgZW5kIHVzZXIgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwgLS0gaW5jbHVkaW5nIHNldHRpbmcgdmFyaWFibGVzLCBtYWtpbmcgZGVjaXNpb25zLCBhbmQgY2FsbGluZyBvcGVyYXRpb25zLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLiBPbmx5IFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSkgY2FuIGJlIG11bHRpcGxheWVyLlxuICpcbiAqIFRoZSBXb3JsZCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgbWFuaXB1bGF0ZSBtdWx0aXBsYXllciB3b3JsZHMgd2l0aGluIHlvdXIgRXBpY2VudGVyIHByb2plY3QuIFlvdSBjYW4gdXNlIHRoaXMgdG8gYWRkIGFuZCByZW1vdmUgZW5kIHVzZXJzIGZyb20gdGhlIHdvcmxkLCBhbmQgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCByZW1vdmUgdGhlaXIgcnVucy4gQmVjYXVzZSBvZiB0aGlzLCB0eXBpY2FsbHkgdGhlIFdvcmxkIEFkYXB0ZXIgaXMgdXNlZCBmb3IgZmFjaWxpdGF0b3IgcGFnZXMgaW4geW91ciBwcm9qZWN0LiAoVGhlIHJlbGF0ZWQgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIvKSBwcm92aWRlcyBhbiBlYXN5IHdheSB0byBhY2Nlc3MgcnVucyBhbmQgd29ybGRzIGZvciBwYXJ0aWN1bGFyIGVuZCB1c2Vycywgc28gaXMgdHlwaWNhbGx5IHVzZWQgaW4gcGFnZXMgdGhhdCBlbmQgdXNlcnMgd2lsbCBpbnRlcmFjdCB3aXRoLilcbiAqXG4gKiBBcyB3aXRoIGFsbCB0aGUgb3RoZXIgW0FQSSBBZGFwdGVyc10oLi4vLi4vKSwgYWxsIG1ldGhvZHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFdvcmxkIEFQSSBTZXJ2aWNlIGRlZmF1bHRzLlxuICpcbiAqIFRvIHVzZSB0aGUgV29ybGQgQWRhcHRlciwgaW5zdGFudGlhdGUgaXQgYW5kIHRoZW4gYWNjZXNzIHRoZSBtZXRob2RzIHByb3ZpZGVkLiBJbnN0YW50aWF0aW5nIHJlcXVpcmVzIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBpbiB0aGUgRXBpY2VudGVyIHVzZXIgaW50ZXJmYWNlKSwgcHJvamVjdCBpZCAoKipQcm9qZWN0IElEKiopLCBhbmQgZ3JvdXAgKCoqR3JvdXAgTmFtZSoqKS5cbiAqXG4gKiAgICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAqICAgICAgIHdhLmNyZWF0ZSgpXG4gKiAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICogICAgICAgICAgICAgIC8vIGNhbGwgbWV0aG9kcywgZS5nLiB3YS5hZGRVc2VycygpXG4gKiAgICAgICAgICB9KTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbi8vIHZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xuXG52YXIgYXBpQmFzZSA9ICdtdWx0aXBsYXllci8nO1xudmFyIGFzc2lnbm1lbnRFbmRwb2ludCA9IGFwaUJhc2UgKyAnYXNzaWduJztcbnZhciBhcGlFbmRwb2ludCA9IGFwaUJhc2UgKyAnd29ybGQnO1xudmFyIHByb2plY3RFbmRwb2ludCA9IGFwaUJhc2UgKyAncHJvamVjdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIHByb2plY3RzIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgcHJvamVjdDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKS4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICBncm91cDogdW5kZWZpbmVkLFxuXG4gICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBtb2RlbCBmaWxlIHRvIHVzZSB0byBjcmVhdGUgcnVucyBpbiB0aGlzIHdvcmxkLiBEZWZhdWx0cyB0byB1bmRlZmluZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBtb2RlbDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgd29ybGQuIEN1cnJlbnRseSBvbmx5IHN1cHBvcnRzIHdvcmxkLWlkcyBhcyBmaWx0ZXJzLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlclxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgaWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge30sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGxlZCB3aGVuIHRoZSBjYWxsIGNvbXBsZXRlcyBzdWNjZXNzZnVsbHkuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBzdWNjZXNzOiAkLm5vb3AsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGxlZCB3aGVuIHRoZSBjYWxsIGZhaWxzLiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgZXJyb3I6ICQubm9vcFxuICAgIH07XG5cbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmlkKSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmlkO1xuICAgIH1cblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB3b3JsZCBpZCBzcGVjaWZpZWQgdG8gYXBwbHkgb3BlcmF0aW9ucyBhZ2FpbnN0LiBUaGlzIGNvdWxkIGhhcHBlbiBpZiB0aGUgdXNlciBpcyBub3QgYXNzaWduZWQgdG8gYSB3b3JsZCBhbmQgaXMgdHJ5aW5nIHRvIHdvcmsgd2l0aCBydW5zIGZyb20gdGhhdCB3b3JsZC4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmICghb3B0aW9ucy5tb2RlbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBtb2RlbCBzcGVjaWZpZWQgdG8gZ2V0IHRoZSBjdXJyZW50IHJ1bicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBXb3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFVzaW5nIHRoaXMgbWV0aG9kIGlzIHJhcmUuIEl0IGlzIG1vcmUgY29tbW9uIHRvIGNyZWF0ZSB3b3JsZHMgYXV0b21hdGljYWxseSB3aGlsZSB5b3UgYGF1dG9Bc3NpZ24oKWAgZW5kIHVzZXJzIHRvIHdvcmxkcy4gKEluIHRoaXMgY2FzZSwgY29uZmlndXJhdGlvbiBkYXRhIGZvciB0aGUgd29ybGQsIHN1Y2ggYXMgdGhlIHJvbGVzLCBhcmUgcmVhZCBmcm9tIHRoZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb24gaW5mb3JtYXRpb24sIGZvciBleGFtcGxlIGJ5IGBnZXRQcm9qZWN0U2V0dGluZ3MoKWAuKVxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKHtcbiAgICAgICAgKiAgICAgICAgICAgcm9sZXM6IFsnVlAgTWFya2V0aW5nJywgJ1ZQIFNhbGVzJywgJ1ZQIEVuZ2luZWVyaW5nJ11cbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIGNyZWF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZ3JvdXBgIChPcHRpb25hbCkgVGhlICoqR3JvdXAgTmFtZSoqIHRvIGNyZWF0ZSB0aGlzIHdvcmxkIHVuZGVyLiBPbmx5IGVuZCB1c2VycyBpbiB0aGlzIGdyb3VwIGFyZSBlbGlnaWJsZSB0byBqb2luIHRoZSB3b3JsZC4gT3B0aW9uYWwgaGVyZTsgcmVxdWlyZWQgd2hlbiBpbnN0YW50aWF0aW5nIHRoZSBzZXJ2aWNlIChgbmV3IEYuc2VydmljZS5Xb3JsZCgpYCkuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMucm9sZXNgIChPcHRpb25hbCkgVGhlIGxpc3Qgb2Ygcm9sZXMgKHN0cmluZ3MpIGZvciB0aGlzIHdvcmxkLiBTb21lIHdvcmxkcyBoYXZlIHNwZWNpZmljIHJvbGVzIHRoYXQgKiptdXN0KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgcm9sZXMgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIHVzZXJzIHRvIHdvcmxkcyBhbmQgZW5zdXJlIHRoYXQgYWxsIHJvbGVzIGFyZSBmaWxsZWQgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtcy5vcHRpb25hbFJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIG9wdGlvbmFsIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbWF5KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgb3B0aW9uYWwgcm9sZXMgYXMgcGFydCBvZiB0aGUgd29ybGQgb2JqZWN0IGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtpbnRlZ2VyfSBgcGFyYW1zLm1pblVzZXJzYCAoT3B0aW9uYWwpIFRoZSBtaW5pbXVtIG51bWJlciBvZiB1c2VycyBmb3IgdGhlIHdvcmxkLiBJbmNsdWRpbmcgdGhpcyBudW1iZXIgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIGVuZCB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IHRoZSBjb3JyZWN0IG51bWJlciBvZiB1c2VycyBhcmUgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9KTtcbiAgICAgICAgICAgIHZhciB3b3JsZEFwaVBhcmFtcyA9IFsnc2NvcGUnLCAnZmlsZXMnLCAncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycycsICdncm91cCcsICduYW1lJ107XG4gICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgd29ybGRBcGlQYXJhbXMpO1xuXG4gICAgICAgICAgICAvLyBhY2NvdW50IGFuZCBwcm9qZWN0IGdvIGluIHRoZSBib2R5LCBub3QgaW4gdGhlIHVybFxuICAgICAgICAgICAgJC5leHRlbmQocGFyYW1zLCBfcGljayhzZXJ2aWNlT3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSkpO1xuXG4gICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IGNyZWF0ZU9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgICAgIGNyZWF0ZU9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJlc3BvbnNlLmlkOyAvL2FsbCBmdXR1cmUgY2hhaW5lZCBjYWxscyB0byBvcGVyYXRlIG9uIHRoaXMgaWRcbiAgICAgICAgICAgICAgICByZXR1cm4gb2xkU3VjY2Vzcy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgYSBXb3JsZCwgZm9yIGV4YW1wbGUgdG8gcmVwbGFjZSB0aGUgcm9sZXMgaW4gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogVHlwaWNhbGx5LCB5b3UgY29tcGxldGUgd29ybGQgY29uZmlndXJhdGlvbiBhdCB0aGUgcHJvamVjdCBsZXZlbCwgcmF0aGVyIHRoYW4gYXQgdGhlIHdvcmxkIGxldmVsLiBGb3IgZXhhbXBsZSwgZWFjaCB3b3JsZCBpbiB5b3VyIHByb2plY3QgcHJvYmFibHkgaGFzIHRoZSBzYW1lIHJvbGVzIGZvciBlbmQgdXNlcnMuIEFuZCB5b3VyIHByb2plY3QgaXMgcHJvYmFibHkgZWl0aGVyIGNvbmZpZ3VyZWQgc28gdGhhdCBhbGwgZW5kIHVzZXJzIHNoYXJlIHRoZSBzYW1lIHdvcmxkIChhbmQgcnVuKSwgb3Igc21hbGxlciBzZXRzIG9mIGVuZCB1c2VycyBzaGFyZSB3b3JsZHMg4oCUIGJ1dCBub3QgYm90aC4gSG93ZXZlciwgdGhpcyBtZXRob2QgaXMgYXZhaWxhYmxlIGlmIHlvdSBuZWVkIHRvIHVwZGF0ZSB0aGUgY29uZmlndXJhdGlvbiBvZiBhIHBhcnRpY3VsYXIgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EudXBkYXRlKHsgcm9sZXM6IFsnVlAgTWFya2V0aW5nJywgJ1ZQIFNhbGVzJywgJ1ZQIEVuZ2luZWVyaW5nJ10gfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gdXBkYXRlIHRoZSB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5uYW1lYCBBIHN0cmluZyBpZGVudGlmaWVyIGZvciB0aGUgbGlua2VkIGVuZCB1c2VycywgZm9yIGV4YW1wbGUsIFwibmFtZVwiOiBcIk91ciBUZWFtXCIuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMucm9sZXNgIChPcHRpb25hbCkgVGhlIGxpc3Qgb2Ygcm9sZXMgKHN0cmluZ3MpIGZvciB0aGlzIHdvcmxkLiBTb21lIHdvcmxkcyBoYXZlIHNwZWNpZmljIHJvbGVzIHRoYXQgKiptdXN0KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgcm9sZXMgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIHVzZXJzIHRvIHdvcmxkcyBhbmQgZW5zdXJlIHRoYXQgYWxsIHJvbGVzIGFyZSBmaWxsZWQgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtcy5vcHRpb25hbFJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIG9wdGlvbmFsIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbWF5KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgb3B0aW9uYWwgcm9sZXMgYXMgcGFydCBvZiB0aGUgd29ybGQgb2JqZWN0IGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtpbnRlZ2VyfSBgcGFyYW1zLm1pblVzZXJzYCAoT3B0aW9uYWwpIFRoZSBtaW5pbXVtIG51bWJlciBvZiB1c2VycyBmb3IgdGhlIHdvcmxkLiBJbmNsdWRpbmcgdGhpcyBudW1iZXIgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIGVuZCB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IHRoZSBjb3JyZWN0IG51bWJlciBvZiB1c2VycyBhcmUgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgdXBkYXRlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgd2hpdGVsaXN0ID0gWydyb2xlcycsICdvcHRpb25hbFJvbGVzJywgJ21pblVzZXJzJ107XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMgfHwge30sIHdoaXRlbGlzdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKHBhcmFtcywgdXBkYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogRGVsZXRlcyBhbiBleGlzdGluZyB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFRoaXMgZnVuY3Rpb24gb3B0aW9uYWxseSB0YWtlcyBvbmUgYXJndW1lbnQuIElmIHRoZSBhcmd1bWVudCBpcyBhIHN0cmluZywgaXQgaXMgdGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUuIElmIHRoZSBhcmd1bWVudCBpcyBhbiBvYmplY3QsIGl0IGlzIHRoZSBvdmVycmlkZSBmb3IgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZGVsZXRlKCk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtTdHJpbmd8T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBUaGUgaWQgb2YgdGhlIHdvcmxkIHRvIGRlbGV0ZSwgb3Igb3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IChvcHRpb25zICYmICh0eXBlb2Ygb3B0aW9ucyA9PT0gJ3N0cmluZycpKSA/IHsgZmlsdGVyOiBvcHRpb25zIH0gOiB7fTtcbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogVXBkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBmb3IgdGhlIGN1cnJlbnQgaW5zdGFuY2Ugb2YgdGhlIFdvcmxkIEFQSSBBZGFwdGVyIChpbmNsdWRpbmcgYWxsIHN1YnNlcXVlbnQgZnVuY3Rpb24gY2FsbHMsIHVudGlsIHRoZSBjb25maWd1cmF0aW9uIGlzIHVwZGF0ZWQgYWdhaW4pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7Li4ufSkudXBkYXRlQ29uZmlnKHsgZmlsdGVyOiAnMTIzJyB9KS5hZGRVc2VyKHsgdXNlcklkOiAnMTIzJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBjb25maWdgIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB0byB1c2UgaW4gdXBkYXRpbmcgZXhpc3RpbmcgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKi9cbiAgICAgICAgdXBkYXRlQ29uZmlnOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICAkLmV4dGVuZChzZXJ2aWNlT3B0aW9ucywgY29uZmlnKTtcblxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogTGlzdHMgYWxsIHdvcmxkcyBmb3IgYSBnaXZlbiBhY2NvdW50LCBwcm9qZWN0LCBhbmQgZ3JvdXAuIEFsbCB0aHJlZSBhcmUgcmVxdWlyZWQsIGFuZCBpZiBub3Qgc3BlY2lmaWVkIGFzIHBhcmFtZXRlcnMsIGFyZSByZWFkIGZyb20gdGhlIHNlcnZpY2UuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gbGlzdHMgYWxsIHdvcmxkcyBpbiBncm91cCBcInRlYW0xXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgICAgICAgLy8gbGlzdHMgYWxsIHdvcmxkcyBpbiBncm91cCBcIm90aGVyLWdyb3VwLW5hbWVcIlxuICAgICAgICAqICAgICAgICAgICAgICAgd2EubGlzdCh7IGdyb3VwOiAnb3RoZXItZ3JvdXAtbmFtZScgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIGZpbHRlcnMgPSBfcGljayhnZXRPcHRpb25zLCBbJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCddKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgYWxsIHdvcmxkcyB0aGF0IGFuIGVuZCB1c2VyIGJlbG9uZ3MgdG8gZm9yIGEgZ2l2ZW4gYWNjb3VudCAodGVhbSksIHByb2plY3QsIGFuZCBncm91cC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRXb3JsZHNGb3JVc2VyKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnKVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJJZGAgVGhlIGB1c2VySWRgIG9mIHRoZSB1c2VyIHdob3NlIHdvcmxkcyBhcmUgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0V29ybGRzRm9yVXNlcjogZnVuY3Rpb24gKHVzZXJJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gJC5leHRlbmQoXG4gICAgICAgICAgICAgICAgX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSksXG4gICAgICAgICAgICAgICAgeyB1c2VySWQ6IHVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoZmlsdGVycywgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvYWQgaW5mb3JtYXRpb24gZm9yIGEgc3BlY2lmaWMgd29ybGQuIEFsbCBmdXJ0aGVyIGNhbGxzIHRvIHRoZSB3b3JsZCBzZXJ2aWNlIHdpbGwgdXNlIHRoZSBpZCBwcm92aWRlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGB3b3JsZElkYCBUaGUgaWQgb2YgdGhlIHdvcmxkIHRvIGxvYWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBpZiAod29ybGRJZCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHByb3ZpZGUgYSB3b3JsZGlkIHRvIGxvYWQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnLycgfSk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoJycsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBBZGRzIGFuIGVuZCB1c2VyIG9yIGxpc3Qgb2YgZW5kIHVzZXJzIHRvIGEgZ2l2ZW4gd29ybGQuIFRoZSBlbmQgdXNlciBtdXN0IGJlIGEgbWVtYmVyIG9mIHRoZSBgZ3JvdXBgIHRoYXQgaXMgYXNzb2NpYXRlZCB3aXRoIHRoaXMgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gYWRkIG9uZSB1c2VyXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMyddKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKHsgdXNlcklkOiAnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgcm9sZTogJ1ZQIFNhbGVzJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgICAgICAgLy8gYWRkIHNldmVyYWwgdXNlcnNcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKFtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgTWFya2V0aW5nJyB9LFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgdXNlcklkOiAnOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgIHJvbGU6ICdWUCBFbmdpbmVlcmluZycgfVxuICAgICAgICAqICAgICAgICAgICAgICAgXSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlciB0byBhIHNwZWNpZmljIHdvcmxkXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgd29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHsgZmlsdGVyOiB3b3JsZC5pZCB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fGFycmF5fSBgdXNlcnNgIFVzZXIgaWQsIGFycmF5IG9mIHVzZXIgaWRzLCBvYmplY3QsIG9yIGFycmF5IG9mIG9iamVjdHMgb2YgdGhlIHVzZXJzIHRvIGFkZCB0byB0aGlzIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcnMucm9sZWAgVGhlIGByb2xlYCB0aGUgdXNlciBzaG91bGQgaGF2ZSBpbiB0aGUgd29ybGQuIEl0IGlzIHVwIHRvIHRoZSBjYWxsZXIgdG8gZW5zdXJlLCBpZiBuZWVkZWQsIHRoYXQgdGhlIGByb2xlYCBwYXNzZWQgaW4gaXMgb25lIG9mIHRoZSBgcm9sZXNgIG9yIGBvcHRpb25hbFJvbGVzYCBvZiB0aGlzIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgVGhlIHdvcmxkIHRvIHdoaWNoIHRoZSB1c2VycyBzaG91bGQgYmUgYWRkZWQuIElmIG5vdCBzcGVjaWZpZWQsIHRoZSBmaWx0ZXIgcGFyYW1ldGVyIG9mIHRoZSBgb3B0aW9uc2Agb2JqZWN0IGlzIHVzZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBhZGRVc2VyczogZnVuY3Rpb24gKHVzZXJzLCB3b3JsZElkLCBvcHRpb25zKSB7XG5cbiAgICAgICAgICAgIGlmICghdXNlcnMpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgbGlzdCBvZiB1c2VycyB0byBhZGQgdG8gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG5vcm1hbGl6ZSB0aGUgbGlzdCBvZiB1c2VycyB0byBhbiBhcnJheSBvZiB1c2VyIG9iamVjdHNcbiAgICAgICAgICAgIHVzZXJzID0gJC5tYXAoW10uY29uY2F0KHVzZXJzKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QodSk7XG5cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHUgIT09ICdzdHJpbmcnICYmICFpc09iamVjdCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NvbWUgb2YgdGhlIHVzZXJzIGluIHRoZSBsaXN0IGFyZSBub3QgaW4gdGhlIHZhbGlkIGZvcm1hdDogJyArIHUpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBpc09iamVjdCA/IHUgOiB7IHVzZXJJZDogdSB9O1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIG9wdGlvbnMgd2VyZSBwYXNzZWQgYXMgdGhlIHNlY29uZCBwYXJhbWV0ZXJcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qod29ybGRJZCkgJiYgIW9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zID0gd29ybGRJZDtcbiAgICAgICAgICAgICAgICB3b3JsZElkID0gbnVsbDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIC8vIHdlIG11c3QgaGF2ZSBvcHRpb25zIGJ5IG5vd1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB3b3JsZElkID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZmlsdGVyID0gd29ybGRJZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciB1cGRhdGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2VycycgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh1c2VycywgdXBkYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogVXBkYXRlcyB0aGUgcm9sZSBvZiBhbiBlbmQgdXNlciBpbiBhIGdpdmVuIHdvcmxkLiAoWW91IGNhbiBvbmx5IHVwZGF0ZSBvbmUgZW5kIHVzZXIgYXQgYSB0aW1lLilcbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKS50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnKTtcbiAgICAgICAgKiAgICAgICAgICAgd2EudXBkYXRlVXNlcih7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdsZWFkZXInIH0pO1xuICAgICAgICAqICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgdXNlcmAgVXNlciBvYmplY3Qgd2l0aCBgdXNlcklkYCBhbmQgdGhlIG5ldyBgcm9sZWAuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZVVzZXI6IGZ1bmN0aW9uICh1c2VyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKCF1c2VyIHx8ICF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byB1cGRhdGUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBwYXRjaE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3VzZXJzLycgKyB1c2VyLnVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChfcGljayh1c2VyLCAncm9sZScpLCBwYXRjaE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlbW92ZXMgYW4gZW5kIHVzZXIgZnJvbSBhIGdpdmVuIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKFsnYTZmZTBjMWUtZjRiOC00ZjAxLTlmNWYtMDFjY2Y0YzJlZDQ0JywgJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZSddKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EucmVtb3ZlVXNlcih7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fHN0cmluZ30gYHVzZXJgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQsIG9yIGFuIG9iamVjdCBjb250YWluaW5nIHRoZSBgdXNlcklkYCBmaWVsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIHJlbW92ZVVzZXI6IGZ1bmN0aW9uICh1c2VyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiB1c2VyID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIHVzZXIgPSB7IHVzZXJJZDogdXNlciB9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIXVzZXIudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgbmVlZCB0byBwYXNzIGEgdXNlcklkIHRvIHJlbW92ZSBmcm9tIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3VzZXJzLycgKyB1c2VyLnVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyB0aGUgcnVuIGlkIG9mIGN1cnJlbnQgcnVuIGZvciB0aGUgZ2l2ZW4gd29ybGQuIElmIHRoZSB3b3JsZCBkb2VzIG5vdCBoYXZlIGEgcnVuLCBjcmVhdGVzIGEgbmV3IG9uZSBhbmQgcmV0dXJucyB0aGUgcnVuIGlkLlxuICAgICAgICAqXG4gICAgICAgICogUmVtZW1iZXIgdGhhdCBhIFtydW5dKC4uLy4uL2dsb3NzYXJ5LyNydW4pIGlzIGEgY29sbGVjdGlvbiBvZiBpbnRlcmFjdGlvbnMgd2l0aCBhIHByb2plY3QgYW5kIGl0cyBtb2RlbC4gSW4gdGhlIGNhc2Ugb2YgbXVsdGlwbGF5ZXIgcHJvamVjdHMsIHRoZSBydW4gaXMgc2hhcmVkIGJ5IGFsbCBlbmQgdXNlcnMgaW4gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiAnbW9kZWwucHknIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zLm1vZGVsYCBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIGEgcnVuIGlmIG5lZWRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bklkOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YWxpZGF0ZU1vZGVsT3JUaHJvd0Vycm9yKGdldE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChfcGljayhnZXRPcHRpb25zLCAnbW9kZWwnKSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyB0aGUgY3VycmVudCAobW9zdCByZWNlbnQpIHdvcmxkIGZvciB0aGUgZ2l2ZW4gZW5kIHVzZXIgaW4gdGhlIGdpdmVuIGdyb3VwLiBCcmluZ3MgdGhpcyBtb3N0IHJlY2VudCB3b3JsZCBpbnRvIG1lbW9yeSBpZiBuZWVkZWQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKCc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gdXNlIGRhdGEgZnJvbSB3b3JsZFxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJJZGAgVGhlIGB1c2VySWRgIG9mIHRoZSB1c2VyIHdob3NlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBpcyBiZWluZyByZXRyaWV2ZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgVGhlIG5hbWUgb2YgdGhlIGdyb3VwLiBJZiBub3QgcHJvdmlkZWQsIGRlZmF1bHRzIHRvIHRoZSBncm91cCB1c2VkIHRvIGNyZWF0ZSB0aGUgc2VydmljZS5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkRm9yVXNlcjogZnVuY3Rpb24gKHVzZXJJZCwgZ3JvdXBOYW1lKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHRoaXMuZ2V0V29ybGRzRm9yVXNlcih1c2VySWQsIHsgZ3JvdXA6IGdyb3VwTmFtZSB9KVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gYXNzdW1lIHRoZSBtb3N0IHJlY2VudCB3b3JsZCBhcyB0aGUgJ2FjdGl2ZScgd29ybGRcbiAgICAgICAgICAgICAgICAgICAgd29ybGRzLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIubGFzdE1vZGlmaWVkKSAtIG5ldyBEYXRlKGEubGFzdE1vZGlmaWVkKTsgfSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGQgPSB3b3JsZHNbMF07XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGN1cnJlbnRXb3JsZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gIGN1cnJlbnRXb3JsZC5pZDtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGN1cnJlbnRXb3JsZCwgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgdGhlIGN1cnJlbnQgcnVuIGZyb20gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogKE5vdGUgdGhhdCB0aGUgd29ybGQgaWQgcmVtYWlucyBwYXJ0IG9mIHRoZSBydW4gcmVjb3JkLCBpbmRpY2F0aW5nIHRoYXQgdGhlIHJ1biB3YXMgZm9ybWVybHkgYW4gYWN0aXZlIHJ1biBmb3IgdGhlIHdvcmxkLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZGVsZXRlUnVuKCdzYW1wbGUtd29ybGQtaWQnKTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgVGhlIGB3b3JsZElkYCBvZiB0aGUgd29ybGQgZnJvbSB3aGljaCB0aGUgY3VycmVudCBydW4gaXMgYmVpbmcgZGVsZXRlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZVJ1bjogZnVuY3Rpb24gKHdvcmxkSWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBpZiAod29ybGRJZCkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZmlsdGVyID0gd29ybGRJZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkZWxldGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy9ydW4nIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmRlbGV0ZShudWxsLCBkZWxldGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBDcmVhdGVzIGEgbmV3IHJ1biBmb3IgdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKCc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB3YS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB3b3JsZElkYCB3b3JsZElkIGluIHdoaWNoIHdlIGNyZWF0ZSB0aGUgbmV3IHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zLm1vZGVsYCBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIGEgcnVuIGlmIG5lZWRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgbmV3UnVuRm9yV29ybGQ6IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY3VycmVudFJ1bk9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgZmlsdGVyOiB3b3JsZElkIHx8IHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihjdXJyZW50UnVuT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzLmRlbGV0ZVJ1bih3b3JsZElkLCBvcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLmdldEN1cnJlbnRSdW5JZChjdXJyZW50UnVuT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQXNzaWducyBlbmQgdXNlcnMgdG8gd29ybGRzLCBjcmVhdGluZyBuZXcgd29ybGRzIGFzIGFwcHJvcHJpYXRlLCBhdXRvbWF0aWNhbGx5LiBBc3NpZ25zIGFsbCBlbmQgdXNlcnMgaW4gdGhlIGdyb3VwLCBhbmQgY3JlYXRlcyBuZXcgd29ybGRzIGFzIG5lZWRlZCBiYXNlZCBvbiB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIChyb2xlcywgb3B0aW9uYWwgcm9sZXMsIGFuZCBtaW5pbXVtIGVuZCB1c2VycyBwZXIgd29ybGQpLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmF1dG9Bc3NpZ24oKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGF1dG9Bc3NpZ246IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFzc2lnbm1lbnRFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIHBhcmFtcyA9IHtcbiAgICAgICAgICAgICAgICBhY2NvdW50OiBvcHQuYWNjb3VudCxcbiAgICAgICAgICAgICAgICBwcm9qZWN0OiBvcHQucHJvamVjdCxcbiAgICAgICAgICAgICAgICBncm91cDogb3B0Lmdyb3VwXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAob3B0Lm1heFVzZXJzKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zLm1heFVzZXJzID0gb3B0Lm1heFVzZXJzO1xuICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBvcHQpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHByb2plY3QncyB3b3JsZCBjb25maWd1cmF0aW9uLlxuICAgICAgICAqXG4gICAgICAgICogVHlwaWNhbGx5LCBldmVyeSBpbnRlcmFjdGlvbiB3aXRoIHlvdXIgcHJvamVjdCB1c2VzIHRoZSBzYW1lIGNvbmZpZ3VyYXRpb24gb2YgZWFjaCB3b3JsZC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguXG4gICAgICAgICpcbiAgICAgICAgKiAoVGhlIFtNdWx0aXBsYXllciBQcm9qZWN0IFJFU1QgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvbXVsdGlwbGF5ZXJfcHJvamVjdC8pIGFsbG93cyB5b3UgdG8gc2V0IHRoZXNlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbnMuIFRoZSBXb3JsZCBBZGFwdGVyIHNpbXBseSByZXRyaWV2ZXMgdGhlbSwgZm9yIGV4YW1wbGUgc28gdGhleSBjYW4gYmUgdXNlZCBpbiBhdXRvLWFzc2lnbm1lbnQgb2YgZW5kIHVzZXJzIHRvIHdvcmxkcy4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0UHJvamVjdFNldHRpbmdzKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc2V0dGluZ3MpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHNldHRpbmdzLnJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHNldHRpbmdzLm9wdGlvbmFsUm9sZXMpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBnZXRQcm9qZWN0U2V0dGluZ3M6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKHByb2plY3RFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgb3B0LnVybCArPSBbb3B0LmFjY291bnQsIG9wdC5wcm9qZWN0XS5qb2luKCcvJyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChudWxsLCBvcHQpO1xuICAgICAgICB9XG5cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqIEBjbGFzcyBDb29raWUgU3RvcmFnZSBTZXJ2aWNlXG4gKlxuICogQGV4YW1wbGVcbiAqICAgICAgdmFyIHBlb3BsZSA9IHJlcXVpcmUoJ2Nvb2tpZS1zdG9yZScpKHsgcm9vdDogJ3Blb3BsZScgfSk7XG4gICAgICAgIHBlb3BsZVxuICAgICAgICAgICAgLnNhdmUoe2xhc3ROYW1lOiAnc21pdGgnIH0pXG5cbiAqL1xuXG5cbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogTmFtZSBvZiBjb2xsZWN0aW9uXG4gICAgICAgICAqIEB0eXBlIHsgc3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcm9vdDogJy8nLFxuXG4gICAgICAgIGRvbWFpbjogJy5mb3Jpby5jb20nXG4gICAgfTtcbiAgICB0aGlzLnNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLy8gKiBUQkRcbiAgICAgICAgLy8gICogUXVlcnkgY29sbGVjdGlvbjsgdXNlcyBNb25nb0RCIHN5bnRheFxuICAgICAgICAvLyAgKiBAc2VlICA8VEJEOiBEYXRhIEFQSSBVUkw+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gcXMgUXVlcnkgRmlsdGVyXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gbGltaXRlcnMgQHNlZSA8VEJEOiB1cmwgZm9yIGxpbWl0cywgcGFnaW5nIGV0Yz5cbiAgICAgICAgLy8gICpcbiAgICAgICAgLy8gICogQGV4YW1wbGVcbiAgICAgICAgLy8gICogICAgIGNzLnF1ZXJ5KFxuICAgICAgICAvLyAgKiAgICAgIHsgbmFtZTogJ0pvaG4nLCBjbGFzc05hbWU6ICdDU0MxMDEnIH0sXG4gICAgICAgIC8vICAqICAgICAge2xpbWl0OiAxMH1cbiAgICAgICAgLy8gICogICAgIClcblxuICAgICAgICAvLyBxdWVyeTogZnVuY3Rpb24gKHFzLCBsaW1pdGVycykge1xuXG4gICAgICAgIC8vIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgY29va2llIHZhbHVlXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8T2JqZWN0fSBrZXkgICBJZiBnaXZlbiBhIGtleSBzYXZlIHZhbHVlcyB1bmRlciBpdCwgaWYgZ2l2ZW4gYW4gb2JqZWN0IGRpcmVjdGx5LCBzYXZlIHRvIHRvcC1sZXZlbCBhcGlcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSB2YWx1ZSAoT3B0aW9uYWwpXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIE92ZXJyaWRlcyBmb3Igc2VydmljZSBvcHRpb25zXG4gICAgICAgICAqXG4gICAgICAgICAqIEByZXR1cm4geyp9IFRoZSBzYXZlZCB2YWx1ZVxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3Muc2V0KCdwZXJzb24nLCB7IGZpcnN0TmFtZTogJ2pvaG4nLCBsYXN0TmFtZTogJ3NtaXRoJyB9KTtcbiAgICAgICAgICogICAgIGNzLnNldCh7IG5hbWU6J3NtaXRoJywgYWdlOiczMicgfSk7XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgc2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLnNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRvbWFpbiA9IHNldE9wdGlvbnMuZG9tYWluO1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXRPcHRpb25zLnJvb3Q7XG5cbiAgICAgICAgICAgIGRvY3VtZW50LmNvb2tpZSA9IGVuY29kZVVSSUNvbXBvbmVudChrZXkpICsgJz0nICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5jb2RlVVJJQ29tcG9uZW50KHZhbHVlKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChkb21haW4gPyAnOyBkb21haW49JyArIGRvbWFpbiA6ICcnKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwYXRoID8gJzsgcGF0aD0nICsgcGF0aCA6ICcnKTtcblxuICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGNvb2tpZSB2YWx1ZVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5ICAgSWYgZ2l2ZW4gYSBrZXkgc2F2ZSB2YWx1ZXMgdW5kZXIgaXQsIGlmIGdpdmVuIGFuIG9iamVjdCBkaXJlY3RseSwgc2F2ZSB0byB0b3AtbGV2ZWwgYXBpXG4gICAgICAgICAqIEByZXR1cm4geyp9IFRoZSB2YWx1ZSBzdG9yZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLmdldCgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHZhciBjb29raWVSZWcgPSBuZXcgUmVnRXhwKCcoPzooPzpefC4qOylcXFxccyonICsgZW5jb2RlVVJJQ29tcG9uZW50KGtleSkucmVwbGFjZSgvW1xcLVxcLlxcK1xcKl0vZywgJ1xcXFwkJicpICsgJ1xcXFxzKlxcXFw9XFxcXHMqKFteO10qKS4qJCl8Xi4qJCcpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IGRvY3VtZW50LmNvb2tpZS5yZXBsYWNlKGNvb2tpZVJlZywgJyQxJyk7XG4gICAgICAgICAgICB2YWwgPSBkZWNvZGVVUklDb21wb25lbnQodmFsKSB8fCBudWxsO1xuICAgICAgICAgICAgcmV0dXJuIHZhbDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBrZXkgZnJvbSBjb2xsZWN0aW9uXG4gICAgICAgICAqIEBwYXJhbSB7IHN0cmluZ30ga2V5IGtleSB0byByZW1vdmVcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ30ga2V5IFRoZSBrZXkgcmVtb3ZlZFxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3MucmVtb3ZlKCdwZXJzb24nKTtcbiAgICAgICAgICovXG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHJlbU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5zZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSByZW1PcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gcmVtT3B0aW9ucy5yb290O1xuXG4gICAgICAgICAgICBkb2N1bWVudC5jb29raWUgPSBlbmNvZGVVUklDb21wb25lbnQoa2V5KSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJz07IGV4cGlyZXM9VGh1LCAwMSBKYW4gMTk3MCAwMDowMDowMCBHTVQnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwYXRoID8gJzsgcGF0aD0nICsgcGF0aCA6ICcnKTtcbiAgICAgICAgICAgIHJldHVybiBrZXk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMgY29sbGVjdGlvbiBiZWluZyByZWZlcmVuY2VkXG4gICAgICAgICAqIEByZXR1cm4geyBhcnJheX0ga2V5cyBBbGwgdGhlIGtleXMgcmVtb3ZlZFxuICAgICAgICAgKi9cbiAgICAgICAgZGVzdHJveTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFLZXlzID0gZG9jdW1lbnQuY29va2llLnJlcGxhY2UoLygoPzpefFxccyo7KVteXFw9XSspKD89O3wkKXxeXFxzKnxcXHMqKD86XFw9W147XSopPyg/OlxcMXwkKS9nLCAnJykuc3BsaXQoL1xccyooPzpcXD1bXjtdKik/O1xccyovKTtcbiAgICAgICAgICAgIGZvciAodmFyIG5JZHggPSAwOyBuSWR4IDwgYUtleXMubGVuZ3RoOyBuSWR4KyspIHtcbiAgICAgICAgICAgICAgICB2YXIgY29va2llS2V5ID0gZGVjb2RlVVJJQ29tcG9uZW50KGFLZXlzW25JZHhdKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbW92ZShjb29raWVLZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFLZXlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gICAgRGVjaWRlcyB0eXBlIG9mIHN0b3JlIHRvIHByb3ZpZGVcbiovXG5cbid1c2Ugc3RyaWN0Jztcbi8vIHZhciBpc05vZGUgPSBmYWxzZTsgRklYTUU6IEJyb3dzZXJpZnkvbWluaWZ5aWZ5IGhhcyBpc3N1ZXMgd2l0aCB0aGUgbmV4dCBsaW5rXG4vLyB2YXIgc3RvcmUgPSAoaXNOb2RlKSA/IHJlcXVpcmUoJy4vc2Vzc2lvbi1zdG9yZScpIDogcmVxdWlyZSgnLi9jb29raWUtc3RvcmUnKTtcbnZhciBzdG9yZSA9IHJlcXVpcmUoJy4vY29va2llLXN0b3JlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gc3RvcmU7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBxdXRpbHMgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIHVybDogJycsXG5cbiAgICAgICAgY29udGVudFR5cGU6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICAgaGVhZGVyczoge30sXG4gICAgICAgIHN0YXR1c0NvZGU6IHtcbiAgICAgICAgICAgIDQwNDogJC5ub29wXG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9OTFkgZm9yIHN0cmluZ3MgaW4gdGhlIHVybC4gQWxsIEdFVCAmIERFTEVURSBwYXJhbXMgYXJlIHJ1biB0aHJvdWdoIHRoaXNcbiAgICAgICAgICogQHR5cGUge1t0eXBlXSB9XG4gICAgICAgICAqL1xuICAgICAgICBwYXJhbWV0ZXJQYXJzZXI6IHF1dGlscy50b1F1ZXJ5Rm9ybWF0LFxuXG4gICAgICAgIC8vIFRvIGFsbG93IGVwaWNlbnRlci50b2tlbiBhbmQgb3RoZXIgc2Vzc2lvbiBjb29raWVzIHRvIGJlIHBhc3NlZFxuICAgICAgICAvLyB3aXRoIHRoZSByZXF1ZXN0c1xuICAgICAgICB4aHJGaWVsZHM6IHtcbiAgICAgICAgICAgIHdpdGhDcmVkZW50aWFsczogdHJ1ZVxuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHJlc3VsdCA9IGZ1bmN0aW9uIChkKSB7XG4gICAgICAgIHJldHVybiAoJC5pc0Z1bmN0aW9uKGQpKSA/IGQoKSA6IGQ7XG4gICAgfTtcblxuICAgIHZhciBjb25uZWN0ID0gZnVuY3Rpb24gKG1ldGhvZCwgcGFyYW1zLCBjb25uZWN0T3B0aW9ucykge1xuICAgICAgICBwYXJhbXMgPSByZXN1bHQocGFyYW1zKTtcbiAgICAgICAgcGFyYW1zID0gKCQuaXNQbGFpbk9iamVjdChwYXJhbXMpIHx8ICQuaXNBcnJheShwYXJhbXMpKSA/IEpTT04uc3RyaW5naWZ5KHBhcmFtcykgOiBwYXJhbXM7XG5cbiAgICAgICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdHJhbnNwb3J0T3B0aW9ucywgY29ubmVjdE9wdGlvbnMsIHtcbiAgICAgICAgICAgIHR5cGU6IG1ldGhvZCxcbiAgICAgICAgICAgIGRhdGE6IHBhcmFtc1xuICAgICAgICB9KTtcbiAgICAgICAgdmFyIEFMTE9XRURfVE9fQkVfRlVOQ1RJT05TID0gWydkYXRhJywgJ3VybCddO1xuICAgICAgICAkLmVhY2gob3B0aW9ucywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgIGlmICgkLmlzRnVuY3Rpb24odmFsdWUpICYmICQuaW5BcnJheShrZXksIEFMTE9XRURfVE9fQkVfRlVOQ1RJT05TKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zW2tleV0gPSB2YWx1ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAob3B0aW9ucy5sb2dMZXZlbCAmJiBvcHRpb25zLmxvZ0xldmVsID09PSAnREVCVUcnKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhvcHRpb25zLnVybCk7XG4gICAgICAgICAgICB2YXIgb2xkU3VjY2Vzc0ZuID0gb3B0aW9ucy5zdWNjZXNzIHx8ICQubm9vcDtcbiAgICAgICAgICAgIG9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSwgYWpheFN0YXR1cywgYWpheFJlcSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICBvbGRTdWNjZXNzRm4uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYmVmb3JlU2VuZCA9IG9wdGlvbnMuYmVmb3JlU2VuZDtcbiAgICAgICAgb3B0aW9ucy5iZWZvcmVTZW5kID0gZnVuY3Rpb24gKHhociwgc2V0dGluZ3MpIHtcbiAgICAgICAgICAgIHhoci5yZXF1ZXN0VXJsID0gKGNvbm5lY3RPcHRpb25zIHx8IHt9KS51cmw7XG4gICAgICAgICAgICBpZiAoYmVmb3JlU2VuZCkge1xuICAgICAgICAgICAgICAgIGJlZm9yZVNlbmQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gJC5hamF4KG9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICBnZXQ6ZnVuY3Rpb24gKHBhcmFtcywgYWpheE9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRyYW5zcG9ydE9wdGlvbnMsIGFqYXhPcHRpb25zKTtcbiAgICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1ldGVyUGFyc2VyKHJlc3VsdChwYXJhbXMpKTtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmNhbGwodGhpcywgJ0dFVCcsIHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgIH0sXG4gICAgICAgIHNwbGl0R2V0OiBmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgfSxcbiAgICAgICAgcG9zdDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwb3N0J10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBwYXRjaDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwYXRjaCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgcHV0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ3B1dCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAocGFyYW1zLCBhamF4T3B0aW9ucykge1xuICAgICAgICAgICAgLy9ERUxFVEUgZG9lc24ndCBzdXBwb3J0IGJvZHkgcGFyYW1zLCBidXQgalF1ZXJ5IHRoaW5rcyBpdCBkb2VzLlxuICAgICAgICAgICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgdHJhbnNwb3J0T3B0aW9ucywgYWpheE9wdGlvbnMpO1xuICAgICAgICAgICAgcGFyYW1zID0gb3B0aW9ucy5wYXJhbWV0ZXJQYXJzZXIocmVzdWx0KHBhcmFtcykpO1xuICAgICAgICAgICAgaWYgKCQudHJpbShwYXJhbXMpKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRlbGltaXRlciA9IChyZXN1bHQob3B0aW9ucy51cmwpLmluZGV4T2YoJz8nKSA9PT0gLTEpID8gJz8nIDogJyYnO1xuICAgICAgICAgICAgICAgIG9wdGlvbnMudXJsID0gcmVzdWx0KG9wdGlvbnMudXJsKSArIGRlbGltaXRlciArIHBhcmFtcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmNhbGwodGhpcywgJ0RFTEVURScsIG51bGwsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuICAgICAgICBoZWFkOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ2hlYWQnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIG9wdGlvbnM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsnb3B0aW9ucyddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICByZXR1cm4gJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbi8vIHZhciBpc05vZGUgPSBmYWxzZTsgRklYTUU6IEJyb3dzZXJpZnkvbWluaWZ5aWZ5IGhhcyBpc3N1ZXMgd2l0aCB0aGUgbmV4dCBsaW5rXG4vLyB2YXIgdHJhbnNwb3J0ID0gKGlzTm9kZSkgPyByZXF1aXJlKCcuL25vZGUtaHR0cC10cmFuc3BvcnQnKSA6IHJlcXVpcmUoJy4vYWpheC1odHRwLXRyYW5zcG9ydCcpO1xudmFyIHRyYW5zcG9ydCA9IHJlcXVpcmUoJy4vYWpheC1odHRwLXRyYW5zcG9ydCcpO1xubW9kdWxlLmV4cG9ydHMgPSB0cmFuc3BvcnQ7XG4iLCIvKipcbi8qIEluaGVyaXQgZnJvbSBhIGNsYXNzICh1c2luZyBwcm90b3R5cGUgYm9ycm93aW5nKVxuKi9cbid1c2Ugc3RyaWN0JztcblxuZnVuY3Rpb24gaW5oZXJpdChDLCBQKSB7XG4gICAgdmFyIEYgPSBmdW5jdGlvbiAoKSB7fTtcbiAgICBGLnByb3RvdHlwZSA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlID0gbmV3IEYoKTtcbiAgICBDLl9fc3VwZXIgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEM7XG59XG5cbi8qKlxuKiBTaGFsbG93IGNvcHkgb2YgYW4gb2JqZWN0XG4qL1xudmFyIGV4dGVuZCA9IGZ1bmN0aW9uIChkZXN0IC8qLCB2YXJfYXJncyovKSB7XG4gICAgdmFyIG9iaiA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgdmFyIGN1cnJlbnQ7XG4gICAgZm9yICh2YXIgaiA9IDA7IGo8b2JqLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIGlmICghKGN1cnJlbnQgPSBvYmpbal0pKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGRvIG5vdCB3cmFwIGlubmVyIGluIGRlc3QuaGFzT3duUHJvcGVydHkgb3IgYmFkIHRoaW5ncyB3aWxsIGhhcHBlblxuICAgICAgICAvKmpzaGludCAtVzA4OSAqL1xuICAgICAgICBmb3IgKHZhciBrZXkgaW4gY3VycmVudCkge1xuICAgICAgICAgICAgZGVzdFtrZXldID0gY3VycmVudFtrZXldO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGRlc3Q7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChiYXNlLCBwcm9wcywgc3RhdGljUHJvcHMpIHtcbiAgICB2YXIgcGFyZW50ID0gYmFzZTtcbiAgICB2YXIgY2hpbGQ7XG5cbiAgICBjaGlsZCA9IHByb3BzICYmIHByb3BzLmhhc093blByb3BlcnR5KCdjb25zdHJ1Y3RvcicpID8gcHJvcHMuY29uc3RydWN0b3IgOiBmdW5jdGlvbiAoKSB7IHJldHVybiBwYXJlbnQuYXBwbHkodGhpcywgYXJndW1lbnRzKTsgfTtcblxuICAgIC8vIGFkZCBzdGF0aWMgcHJvcGVydGllcyB0byB0aGUgY2hpbGQgY29uc3RydWN0b3IgZnVuY3Rpb25cbiAgICBleHRlbmQoY2hpbGQsIHBhcmVudCwgc3RhdGljUHJvcHMpO1xuXG4gICAgLy8gYXNzb2NpYXRlIHByb3RvdHlwZSBjaGFpblxuICAgIGluaGVyaXQoY2hpbGQsIHBhcmVudCk7XG5cbiAgICAvLyBhZGQgaW5zdGFuY2UgcHJvcGVydGllc1xuICAgIGlmIChwcm9wcykge1xuICAgICAgICBleHRlbmQoY2hpbGQucHJvdG90eXBlLCBwcm9wcyk7XG4gICAgfVxuXG4gICAgLy8gZG9uZVxuICAgIHJldHVybiBjaGlsZDtcbn07XG4iLCIndXNlIHN0cmljdCc7XG4vKmpzaGludCBsb29wZnVuYzpmYWxzZSAqL1xuXG5mdW5jdGlvbiBfdyh2YWwpIHtcbiAgICBpZiAodmFsICYmIHZhbC50aGVuKSB7XG4gICAgICAgIHJldHVybiB2YWw7XG4gICAgfVxuICAgIHZhciBwID0gJC5EZWZlcnJlZCgpO1xuICAgIHAucmVzb2x2ZSh2YWwpO1xuXG4gICAgcmV0dXJuIHAucHJvbWlzZSgpO1xufVxuXG5mdW5jdGlvbiBzZXEoKSB7XG4gICAgdmFyIGxpc3QgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuYXBwbHkoYXJndW1lbnRzKTtcblxuICAgIGZ1bmN0aW9uIG5leHQocCkge1xuICAgICAgICB2YXIgY3VyID0gbGlzdC5zcGxpY2UoMCwxKVswXTtcblxuICAgICAgICBpZiAoIWN1cikge1xuICAgICAgICAgICAgcmV0dXJuIHA7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX3coY3VyKHApKS50aGVuKG5leHQpO1xuICAgIH1cblxuICAgIHJldHVybiBmdW5jdGlvbiAoc2VlZCkge1xuICAgICAgICByZXR1cm4gbmV4dChzZWVkKS5mYWlsKHNlcS5mYWlsKTtcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBNYWtlU2VxKG9iaikge1xuICAgIHZhciByZXMgPSB7XG4gICAgICAgIF9fY2FsbHM6IFtdLFxuXG4gICAgICAgIG9yaWdpbmFsOiBvYmosXG5cbiAgICAgICAgdGhlbjogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgICAgICB0aGlzLl9fY2FsbHMucHVzaChmbik7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfSxcblxuICAgICAgICBzdGFydDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgICAgICAgICAgLy8gY2xlYW4gdXBcbiAgICAgICAgICAgIHRoaXMudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMuX19jYWxscy5sZW5ndGggPSAwO1xuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIHNlcS5hcHBseShudWxsLCB0aGlzLl9fY2FsbHMpKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgZmFpbDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgICAgICBzZXEuZmFpbCA9IGZuO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIGZ1bmNNYWtlciA9IGZ1bmN0aW9uIChwLCBvYmopIHtcbiAgICAgICAgdmFyIGZuID0gb2JqW3BdLmJpbmQob2JqKTtcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmFwcGx5KGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB0aGlzLl9fY2FsbHMucHVzaChGdW5jdGlvbi5iaW5kLmFwcGx5KGZuLCBbbnVsbF0uY29uY2F0KGFyZ3MpKSk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfTtcbiAgICB9O1xuXG4gICAgZm9yICh2YXIgcHJvcCBpbiBvYmopIHtcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpbcHJvcF0gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIHJlc1twcm9wXSA9IGZ1bmNNYWtlcihwcm9wLCBvYmopO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVzW3Byb3BdID0gb2JqW3Byb3BdO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlcztcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBNYWtlU2VxO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBfcGljazogZnVuY3Rpb24gKG9iaiwgcHJvcHMpIHtcbiAgICAgICAgdmFyIHJlcyA9IHt9O1xuICAgICAgICBmb3IgKHZhciBwIGluIG9iaikge1xuICAgICAgICAgICAgaWYgKHByb3BzLmluZGV4T2YocCkgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgcmVzW3BdID0gb2JqW3BdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG59O1xuIiwiLyoqXG4gKiBVdGlsaXRpZXMgZm9yIHdvcmtpbmcgd2l0aCBxdWVyeSBzdHJpbmdzXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IChmdW5jdGlvbiAoKSB7XG5cbiAgICByZXR1cm4ge1xuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgdG8gbWF0cml4IGZvcm1hdFxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IHFzIE9iamVjdCB0byBjb252ZXJ0IHRvIHF1ZXJ5IHN0cmluZ1xuICAgICAgICAgKiBAcmV0dXJuIHsgc3RyaW5nfSAgICBNYXRyaXgtZm9ybWF0IHF1ZXJ5IHBhcmFtZXRlcnNcbiAgICAgICAgICovXG4gICAgICAgIHRvTWF0cml4Rm9ybWF0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkIHx8IHFzID09PSAnJykge1xuICAgICAgICAgICAgICAgIHJldHVybiAnOyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodHlwZW9mIHFzID09PSAnc3RyaW5nJyB8fCBxcyBpbnN0YW5jZW9mIFN0cmluZykge1xuICAgICAgICAgICAgICAgIHJldHVybiBxcztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJldHVybkFycmF5ID0gW107XG4gICAgICAgICAgICB2YXIgT1BFUkFUT1JTID0gWyc8JywgJz4nLCAnISddO1xuICAgICAgICAgICAgJC5lYWNoKHFzLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnIHx8ICQuaW5BcnJheSgkLnRyaW0odmFsdWUpLmNoYXJBdCgwKSwgT1BFUkFUT1JTKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSAnPScgKyB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuQXJyYXkucHVzaChrZXkgKyB2YWx1ZSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdmFyIG10cnggPSAnOycgKyByZXR1cm5BcnJheS5qb2luKCc7Jyk7XG4gICAgICAgICAgICByZXR1cm4gbXRyeDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgc3RyaW5ncy9hcnJheXMvb2JqZWN0cyB0byB0eXBlICdhPWImYj1jJ1xuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXNcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRvUXVlcnlGb3JtYXQ6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodHlwZW9mIHFzID09PSAnc3RyaW5nJyB8fCBxcyBpbnN0YW5jZW9mIFN0cmluZykge1xuICAgICAgICAgICAgICAgIHJldHVybiBxcztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJldHVybkFycmF5ID0gW107XG4gICAgICAgICAgICAkLmVhY2gocXMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgaWYgKCQuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZS5qb2luKCcsJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vTW9zdGx5IGZvciBkYXRhIGFwaVxuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuQXJyYXkucHVzaChrZXkgKyAnPScgKyB2YWx1ZSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJldHVybkFycmF5LmpvaW4oJyYnKTtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHN0cmluZ3Mgb2YgdHlwZSAnYT1iJmI9YycgdG8geyBhOmIsIGI6Y31cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ30gcXNcbiAgICAgICAgICogQHJldHVybiB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgcXNUb09iamVjdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCB8fCBxcyA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge307XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBxc0FycmF5ID0gcXMuc3BsaXQoJyYnKTtcbiAgICAgICAgICAgIHZhciByZXR1cm5PYmogPSB7fTtcbiAgICAgICAgICAgICQuZWFjaChxc0FycmF5LCBmdW5jdGlvbiAoaW5kZXgsIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgdmFyIHFLZXkgPSB2YWx1ZS5zcGxpdCgnPScpWzBdO1xuICAgICAgICAgICAgICAgIHZhciBxVmFsID0gdmFsdWUuc3BsaXQoJz0nKVsxXTtcblxuICAgICAgICAgICAgICAgIGlmIChxVmFsLmluZGV4T2YoJywnKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgcVZhbCA9IHFWYWwuc3BsaXQoJywnKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpbcUtleV0gPSBxVmFsO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiByZXR1cm5PYmo7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5vcm1hbGl6ZXMgYW5kIG1lcmdlcyBzdHJpbmdzIG9mIHR5cGUgJ2E9YicsIHsgYjpjfSB0byB7IGE6YiwgYjpjfVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXMxXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxczJcbiAgICAgICAgICogQHJldHVybiB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgbWVyZ2VRUzogZnVuY3Rpb24gKHFzMSwgcXMyKSB7XG4gICAgICAgICAgICB2YXIgb2JqMSA9IHRoaXMucXNUb09iamVjdCh0aGlzLnRvUXVlcnlGb3JtYXQocXMxKSk7XG4gICAgICAgICAgICB2YXIgb2JqMiA9IHRoaXMucXNUb09iamVjdCh0aGlzLnRvUXVlcnlGb3JtYXQocXMyKSk7XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIG9iajEsIG9iajIpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGFkZFRyYWlsaW5nU2xhc2g6IGZ1bmN0aW9uICh1cmwpIHtcbiAgICAgICAgICAgIGlmICghdXJsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuICh1cmwuY2hhckF0KHVybC5sZW5ndGggLSAxKSA9PT0gJy8nKSA/IHVybCA6ICh1cmwgKyAnLycpO1xuICAgICAgICB9XG4gICAgfTtcbn0oKSk7XG5cblxuXG4iLCIvKipcbiAqIFV0aWxpdGllcyBmb3Igd29ya2luZyB3aXRoIHRoZSBydW4gc2VydmljZVxuKi9cbid1c2Ugc3RyaWN0JztcbnZhciBxdXRpbCA9IHJlcXVpcmUoJy4vcXVlcnktdXRpbCcpO1xudmFyIE1BWF9VUkxfTEVOR1RIID0gMjA0ODtcblxubW9kdWxlLmV4cG9ydHMgPSAoZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiByZXR1cm5zIG9wZXJhdGlvbnMgb2YgdGhlIGZvcm0gYFtbb3AxLG9wMl0sIFthcmcxLCBhcmcyXV1gXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdHxBcnJheXxTdHJpbmd9IGBvcGVyYXRpb25zYCBvcGVyYXRpb25zIHRvIHBlcmZvcm1cbiAgICAgICAgICogQHBhcmFtICB7QXJyYXl9IGBhcmdzYCBhcmd1bWVudHMgZm9yIG9wZXJhdGlvblxuICAgICAgICAgKiBAcmV0dXJuIHtTdHJpbmd9ICAgIE1hdHJpeC1mb3JtYXQgcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAgKi9cbiAgICAgICAgbm9ybWFsaXplT3BlcmF0aW9uczogZnVuY3Rpb24gKG9wZXJhdGlvbnMsIGFyZ3MpIHtcbiAgICAgICAgICAgIGlmICghYXJncykge1xuICAgICAgICAgICAgICAgIGFyZ3MgPSBbXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciByZXR1cm5MaXN0ID0ge1xuICAgICAgICAgICAgICAgIG9wczogW10sXG4gICAgICAgICAgICAgICAgYXJnczogW11cbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfY29uY2F0ID0gZnVuY3Rpb24gKGFycikge1xuICAgICAgICAgICAgICAgIHJldHVybiAoYXJyICE9PSBudWxsICYmIGFyciAhPT0gdW5kZWZpbmVkKSA/IFtdLmNvbmNhdChhcnIpIDogW107XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAvL3sgYWRkOiBbMSwyXSwgc3VidHJhY3Q6IFsyLDRdIH1cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplUGxhaW5PYmplY3RzID0gZnVuY3Rpb24gKG9wZXJhdGlvbnMsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJC5lYWNoKG9wZXJhdGlvbnMsIGZ1bmN0aW9uIChvcG4sIGFyZykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wbik7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQoYXJnKSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgLy97IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxXSB9XG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZVN0cnVjdHVyZWRPYmplY3RzID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wZXJhdGlvbi5uYW1lKTtcbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KG9wZXJhdGlvbi5wYXJhbXMpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplT2JqZWN0ID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAoKG9wZXJhdGlvbi5uYW1lKSA/IF9ub3JtYWxpemVTdHJ1Y3R1cmVkT2JqZWN0cyA6IF9ub3JtYWxpemVQbGFpbk9iamVjdHMpKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZUxpdGVyYWxzID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgYXJncywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wZXJhdGlvbik7XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChhcmdzKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplQXJyYXlzID0gZnVuY3Rpb24gKG9wZXJhdGlvbnMsIGFyZywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAkLmVhY2gob3BlcmF0aW9ucywgZnVuY3Rpb24gKGluZGV4LCBvcG4pIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChvcG4pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfbm9ybWFsaXplT2JqZWN0KG9wbiwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfbm9ybWFsaXplTGl0ZXJhbHMob3BuLCBhcmdzW2luZGV4XSwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qob3BlcmF0aW9ucykpIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplT2JqZWN0KG9wZXJhdGlvbnMsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICgkLmlzQXJyYXkob3BlcmF0aW9ucykpIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplQXJyYXlzKG9wZXJhdGlvbnMsIGFyZ3MsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplTGl0ZXJhbHMob3BlcmF0aW9ucywgYXJncywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICB9LFxuXG4gICAgICAgIHNwbGl0R2V0RmFjdG9yeTogZnVuY3Rpb24gKGh0dHBPcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgICAgIHZhciBodHRwID0gdGhpcztcbiAgICAgICAgICAgICAgICB2YXIgZ2V0VmFsdWUgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmFsdWUgPSBvcHRpb25zW25hbWVdIHx8IGh0dHBPcHRpb25zW25hbWVdO1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGdldEZpbmFsVXJsID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdXJsID0gZ2V0VmFsdWUoJ3VybCcsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IHBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlcmUgaXMgZWFzeSAob3Iga25vd24pIHdheSB0byBnZXQgdGhlIGZpbmFsIFVSTCBqcXVlcnkgaXMgZ29pbmcgdG8gc2VuZCBzb1xuICAgICAgICAgICAgICAgICAgICAvLyB3ZSdyZSByZXBsaWNhdGluZyBpdC4gVGhlIHByb2Nlc3MgbWlnaHQgY2hhbmdlIGF0IHNvbWUgcG9pbnQgYnV0IGl0IHByb2JhYmx5IHdpbGwgbm90LlxuICAgICAgICAgICAgICAgICAgICAvLyAxLiBSZW1vdmUgaGFzaFxuICAgICAgICAgICAgICAgICAgICB1cmwgPSB1cmwucmVwbGFjZSgvIy4qJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gQXBwZW5kIHF1ZXJ5IHN0cmluZ1xuICAgICAgICAgICAgICAgICAgICB2YXIgcXVlcnlQYXJhbXMgPSBxdXRpbC50b1F1ZXJ5Rm9ybWF0KGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgcXVlc3Rpb25JZHggPSB1cmwuaW5kZXhPZignPycpO1xuICAgICAgICAgICAgICAgICAgICBpZiAocXVlcnlQYXJhbXMgJiYgcXVlc3Rpb25JZHggPiAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybCArICcmJyArIHF1ZXJ5UGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHF1ZXJ5UGFyYW1zKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsICsgJz8nICsgcXVlcnlQYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybDtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciB1cmwgPSBnZXRGaW5hbFVybChwYXJhbXMpO1xuICAgICAgICAgICAgICAgIC8vIFdlIG11c3Qgc3BsaXQgdGhlIEdFVCBpbiBtdWx0aXBsZSBzaG9ydCBVUkwnc1xuICAgICAgICAgICAgICAgIC8vIFRoZSBvbmx5IHByb3BlcnR5IGFsbG93ZWQgdG8gYmUgc3BsaXQgaXMgXCJpbmNsdWRlXCJcbiAgICAgICAgICAgICAgICBpZiAocGFyYW1zICYmIHBhcmFtcy5pbmNsdWRlICYmIHVybC5sZW5ndGggPiBNQVhfVVJMX0xFTkdUSCkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgcGFyYW1zQ29weSA9ICQuZXh0ZW5kKHRydWUsIHt9LCBwYXJhbXMpO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgcGFyYW1zQ29weS5pbmNsdWRlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgdXJsTm9JbmNsdWRlcyA9IGdldEZpbmFsVXJsKHBhcmFtc0NvcHkpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZGlmZiA9IE1BWF9VUkxfTEVOR1RIIC0gdXJsTm9JbmNsdWRlcy5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIHZhciBvbGRTdWNjZXNzID0gb3B0aW9ucy5zdWNjZXNzIHx8IGh0dHBPcHRpb25zLnN1Y2Nlc3MgfHwgJC5ub29wO1xuICAgICAgICAgICAgICAgICAgICB2YXIgb2xkRXJyb3IgPSBvcHRpb25zLmVycm9yIHx8IGh0dHBPcHRpb25zLmVycm9yIHx8ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgLy8gcmVtb3ZlIHRoZSBvcmlnaW5hbCBzdWNjZXNzIGFuZCBlcnJvciBjYWxsYmFja3NcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5zdWNjZXNzID0gJC5ub29wO1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmVycm9yID0gJC5ub29wO1xuXG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmNsdWRlID0gcGFyYW1zLmluY2x1ZGU7XG4gICAgICAgICAgICAgICAgICAgIHZhciBjdXJySW5jbHVkZXMgPSBbXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGluY2x1ZGVPcHRzID0gW2N1cnJJbmNsdWRlc107XG4gICAgICAgICAgICAgICAgICAgIHZhciBjdXJyTGVuZ3RoID0gJz9pbmNsdWRlPScubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmFyaWFibGUgPSBpbmNsdWRlLnBvcCgpO1xuICAgICAgICAgICAgICAgICAgICB3aGlsZSAodmFyaWFibGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVzZSBhIGdyZWVkeSBhcHByb2FjaCBmb3Igbm93LCBjYW4gYmUgb3B0aW1pemVkIHRvIGJlIHNvbHZlZCBpbiBhIG1vcmVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGVmZmljaWVudCB3YXlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICsgMSBpcyB0aGUgY29tbWFcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjdXJyTGVuZ3RoICsgdmFyaWFibGUubGVuZ3RoICsgMSA8IGRpZmYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJySW5jbHVkZXMucHVzaCh2YXJpYWJsZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCArPSB2YXJpYWJsZS5sZW5ndGggKyAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJySW5jbHVkZXMgPSBbdmFyaWFibGVdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGVPcHRzLnB1c2goY3VyckluY2x1ZGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyTGVuZ3RoID0gJz9pbmNsdWRlPScubGVuZ3RoICsgdmFyaWFibGUubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUgPSBpbmNsdWRlLnBvcCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHZhciByZXFzID0gJC5tYXAoaW5jbHVkZU9wdHMsIGZ1bmN0aW9uIChpbmNsdWRlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVxUGFyYW1zID0gJC5leHRlbmQoe30sIHBhcmFtcywgeyBpbmNsdWRlOiBpbmNsdWRlIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHJlcVBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAkLndoZW4uYXBwbHkoJCwgcmVxcykudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBFYWNoIGFyZ3VtZW50IGFyZSBhcnJheXMgb2YgdGhlIGFyZ3VtZW50cyBvZiBlYWNoIGRvbmUgcmVxdWVzdFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU28gdGhlIGZpcnN0IGFyZ3VtZW50IG9mIHRoZSBmaXJzdCBhcnJheSBvZiBhcmd1bWVudHMgaXMgdGhlIGRhdGFcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc1ZhbGlkID0gYXJndW1lbnRzWzBdICYmIGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaXNWYWxpZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNob3VsZCBuZXZlciBoYXBwZW4uLi5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRFcnJvcigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBkdGQucmVqZWN0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmlyc3RSZXNwb25zZSA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc09iamVjdCA9ICQuaXNQbGFpbk9iamVjdChmaXJzdFJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc1J1bkFQSSA9IChpc09iamVjdCAmJiAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZS52YXJpYWJsZXMpKSB8fCAhaXNPYmplY3Q7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNSdW5BUEkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSB2YXJpYWJsZXMgcHJvcGVydHkgb25seVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgYWdncmVnYXRlUnVuID0gYXJndW1lbnRzWzBdWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVuID0gYXJnc1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZVJ1bi52YXJpYWJsZXMsIHJ1bi52YXJpYWJsZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkU3VjY2VzcyhhZ2dyZWdhdGVSdW4sIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXJyYXkgb2YgcnVuc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBZ3JlZ2F0ZSB2YXJpYWJsZXMgaW4gZWFjaCBydW5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZWRSdW5zID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChhcmd1bWVudHMsIGZ1bmN0aW9uIChpZHgsIGFyZ3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBydW5zID0gYXJnc1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghJC5pc0FycmF5KHJ1bnMpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKHJ1bnMsIGZ1bmN0aW9uIChpZHhSdW4sIHJ1bikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChydW4uaWQgJiYgIWFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuLnZhcmlhYmxlcyA9IHJ1bi52YXJpYWJsZXMgfHwge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0gPSBydW47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChydW4uaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5leHRlbmQodHJ1ZSwgYWdncmVnYXRlZFJ1bnNbcnVuLmlkXS52YXJpYWJsZXMsIHJ1bi52YXJpYWJsZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdHVybiBpdCBpbnRvIGFuIGFycmF5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZWRSdW5zID0gJC5tYXAoYWdncmVnYXRlZFJ1bnMsIGZ1bmN0aW9uIChydW4pIHsgcmV0dXJuIHJ1bjsgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFJ1bnMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoYWdncmVnYXRlZFJ1bnMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlzIHZhcmlhYmxlcyBBUElcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhZ2dyZWdhdGUgdGhlIHJlc3BvbnNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciB2YXJzID0gYXJnc1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5leHRlbmQodHJ1ZSwgYWdncmVnYXRlZFZhcmlhYmxlcywgdmFycyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkU3VjY2VzcyhhZ2dyZWdhdGVkVmFyaWFibGVzLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvbGRFcnJvci5hcHBseShodHRwLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlamVjdC5hcHBseShkdGQsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQocGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfTtcbn0oKSk7XG4iXX0= +//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL25vZGVfbW9kdWxlcy9pZWVlNzU0L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvaXMtYXJyYXkvaW5kZXguanMiLCJzcmMvYXBpLXZlcnNpb24uanNvbiIsInNyYy9hcHAuanMiLCJzcmMvbWFuYWdlcnMvYXV0aC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2NoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2tleS1uYW1lcy5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9hbHdheXMtbmV3LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2lkZW50aXR5LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL211bHRpcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcC5qcyIsInNyYy9tYW5hZ2Vycy9zY2VuYXJpby1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3NwZWNpYWwtb3BlcmF0aW9ucy5qcyIsInNyYy9tYW5hZ2Vycy93b3JsZC1tYW5hZ2VyLmpzIiwic3JjL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyLmpzIiwic3JjL3N0b3JlL2Nvb2tpZS1zdG9yZS5qcyIsInNyYy9zdG9yZS9zdG9yZS1mYWN0b3J5LmpzIiwic3JjL3RyYW5zcG9ydC9hamF4LWh0dHAtdHJhbnNwb3J0LmpzIiwic3JjL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5LmpzIiwic3JjL3V0aWwvaW5oZXJpdC5qcyIsInNyYy91dGlsL21ha2Utc2VxdWVuY2UuanMiLCJzcmMvdXRpbC9vYmplY3QtdXRpbC5qcyIsInNyYy91dGlsL3F1ZXJ5LXV0aWwuanMiLCJzcmMvdXRpbC9ydW4tdXRpbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN4Z0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxV0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMVRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0UUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25LQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzdUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLyohXG4gKiBUaGUgYnVmZmVyIG1vZHVsZSBmcm9tIG5vZGUuanMsIGZvciB0aGUgYnJvd3Nlci5cbiAqXG4gKiBAYXV0aG9yICAgRmVyb3NzIEFib3VraGFkaWplaCA8ZmVyb3NzQGZlcm9zcy5vcmc+IDxodHRwOi8vZmVyb3NzLm9yZz5cbiAqIEBsaWNlbnNlICBNSVRcbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tcHJvdG8gKi9cblxudmFyIGJhc2U2NCA9IHJlcXVpcmUoJ2Jhc2U2NC1qcycpXG52YXIgaWVlZTc1NCA9IHJlcXVpcmUoJ2llZWU3NTQnKVxudmFyIGlzQXJyYXkgPSByZXF1aXJlKCdpcy1hcnJheScpXG5cbmV4cG9ydHMuQnVmZmVyID0gQnVmZmVyXG5leHBvcnRzLlNsb3dCdWZmZXIgPSBTbG93QnVmZmVyXG5leHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTID0gNTBcbkJ1ZmZlci5wb29sU2l6ZSA9IDgxOTIgLy8gbm90IHVzZWQgYnkgdGhpcyBpbXBsZW1lbnRhdGlvblxuXG52YXIgcm9vdFBhcmVudCA9IHt9XG5cbi8qKlxuICogSWYgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYDpcbiAqICAgPT09IHRydWUgICAgVXNlIFVpbnQ4QXJyYXkgaW1wbGVtZW50YXRpb24gKGZhc3Rlc3QpXG4gKiAgID09PSBmYWxzZSAgIFVzZSBPYmplY3QgaW1wbGVtZW50YXRpb24gKG1vc3QgY29tcGF0aWJsZSwgZXZlbiBJRTYpXG4gKlxuICogQnJvd3NlcnMgdGhhdCBzdXBwb3J0IHR5cGVkIGFycmF5cyBhcmUgSUUgMTArLCBGaXJlZm94IDQrLCBDaHJvbWUgNyssIFNhZmFyaSA1LjErLFxuICogT3BlcmEgMTEuNissIGlPUyA0LjIrLlxuICpcbiAqIER1ZSB0byB2YXJpb3VzIGJyb3dzZXIgYnVncywgc29tZXRpbWVzIHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24gd2lsbCBiZSB1c2VkIGV2ZW5cbiAqIHdoZW4gdGhlIGJyb3dzZXIgc3VwcG9ydHMgdHlwZWQgYXJyYXlzLlxuICpcbiAqIE5vdGU6XG4gKlxuICogICAtIEZpcmVmb3ggNC0yOSBsYWNrcyBzdXBwb3J0IGZvciBhZGRpbmcgbmV3IHByb3BlcnRpZXMgdG8gYFVpbnQ4QXJyYXlgIGluc3RhbmNlcyxcbiAqICAgICBTZWU6IGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTY5NTQzOC5cbiAqXG4gKiAgIC0gU2FmYXJpIDUtNyBsYWNrcyBzdXBwb3J0IGZvciBjaGFuZ2luZyB0aGUgYE9iamVjdC5wcm90b3R5cGUuY29uc3RydWN0b3JgIHByb3BlcnR5XG4gKiAgICAgb24gb2JqZWN0cy5cbiAqXG4gKiAgIC0gQ2hyb21lIDktMTAgaXMgbWlzc2luZyB0aGUgYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbi5cbiAqXG4gKiAgIC0gSUUxMCBoYXMgYSBicm9rZW4gYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGFycmF5cyBvZlxuICogICAgIGluY29ycmVjdCBsZW5ndGggaW4gc29tZSBzaXR1YXRpb25zLlxuXG4gKiBXZSBkZXRlY3QgdGhlc2UgYnVnZ3kgYnJvd3NlcnMgYW5kIHNldCBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgIHRvIGBmYWxzZWAgc28gdGhleVxuICogZ2V0IHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24sIHdoaWNoIGlzIHNsb3dlciBidXQgYmVoYXZlcyBjb3JyZWN0bHkuXG4gKi9cbkJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUID0gZ2xvYmFsLlRZUEVEX0FSUkFZX1NVUFBPUlQgIT09IHVuZGVmaW5lZFxuICA/IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gIDogdHlwZWRBcnJheVN1cHBvcnQoKVxuXG5mdW5jdGlvbiB0eXBlZEFycmF5U3VwcG9ydCAoKSB7XG4gIGZ1bmN0aW9uIEJhciAoKSB7fVxuICB0cnkge1xuICAgIHZhciBhcnIgPSBuZXcgVWludDhBcnJheSgxKVxuICAgIGFyci5mb28gPSBmdW5jdGlvbiAoKSB7IHJldHVybiA0MiB9XG4gICAgYXJyLmNvbnN0cnVjdG9yID0gQmFyXG4gICAgcmV0dXJuIGFyci5mb28oKSA9PT0gNDIgJiYgLy8gdHlwZWQgYXJyYXkgaW5zdGFuY2VzIGNhbiBiZSBhdWdtZW50ZWRcbiAgICAgICAgYXJyLmNvbnN0cnVjdG9yID09PSBCYXIgJiYgLy8gY29uc3RydWN0b3IgY2FuIGJlIHNldFxuICAgICAgICB0eXBlb2YgYXJyLnN1YmFycmF5ID09PSAnZnVuY3Rpb24nICYmIC8vIGNocm9tZSA5LTEwIGxhY2sgYHN1YmFycmF5YFxuICAgICAgICBhcnIuc3ViYXJyYXkoMSwgMSkuYnl0ZUxlbmd0aCA9PT0gMCAvLyBpZTEwIGhhcyBicm9rZW4gYHN1YmFycmF5YFxuICB9IGNhdGNoIChlKSB7XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuZnVuY3Rpb24ga01heExlbmd0aCAoKSB7XG4gIHJldHVybiBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVFxuICAgID8gMHg3ZmZmZmZmZlxuICAgIDogMHgzZmZmZmZmZlxufVxuXG4vKipcbiAqIENsYXNzOiBCdWZmZXJcbiAqID09PT09PT09PT09PT1cbiAqXG4gKiBUaGUgQnVmZmVyIGNvbnN0cnVjdG9yIHJldHVybnMgaW5zdGFuY2VzIG9mIGBVaW50OEFycmF5YCB0aGF0IGFyZSBhdWdtZW50ZWRcbiAqIHdpdGggZnVuY3Rpb24gcHJvcGVydGllcyBmb3IgYWxsIHRoZSBub2RlIGBCdWZmZXJgIEFQSSBmdW5jdGlvbnMuIFdlIHVzZVxuICogYFVpbnQ4QXJyYXlgIHNvIHRoYXQgc3F1YXJlIGJyYWNrZXQgbm90YXRpb24gd29ya3MgYXMgZXhwZWN0ZWQgLS0gaXQgcmV0dXJuc1xuICogYSBzaW5nbGUgb2N0ZXQuXG4gKlxuICogQnkgYXVnbWVudGluZyB0aGUgaW5zdGFuY2VzLCB3ZSBjYW4gYXZvaWQgbW9kaWZ5aW5nIHRoZSBgVWludDhBcnJheWBcbiAqIHByb3RvdHlwZS5cbiAqL1xuZnVuY3Rpb24gQnVmZmVyIChhcmcpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIEJ1ZmZlcikpIHtcbiAgICAvLyBBdm9pZCBnb2luZyB0aHJvdWdoIGFuIEFyZ3VtZW50c0FkYXB0b3JUcmFtcG9saW5lIGluIHRoZSBjb21tb24gY2FzZS5cbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIHJldHVybiBuZXcgQnVmZmVyKGFyZywgYXJndW1lbnRzWzFdKVxuICAgIHJldHVybiBuZXcgQnVmZmVyKGFyZylcbiAgfVxuXG4gIHRoaXMubGVuZ3RoID0gMFxuICB0aGlzLnBhcmVudCA9IHVuZGVmaW5lZFxuXG4gIC8vIENvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ251bWJlcicpIHtcbiAgICByZXR1cm4gZnJvbU51bWJlcih0aGlzLCBhcmcpXG4gIH1cblxuICAvLyBTbGlnaHRseSBsZXNzIGNvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gZnJvbVN0cmluZyh0aGlzLCBhcmcsIGFyZ3VtZW50cy5sZW5ndGggPiAxID8gYXJndW1lbnRzWzFdIDogJ3V0ZjgnKVxuICB9XG5cbiAgLy8gVW51c3VhbC5cbiAgcmV0dXJuIGZyb21PYmplY3QodGhpcywgYXJnKVxufVxuXG5mdW5jdGlvbiBmcm9tTnVtYmVyICh0aGF0LCBsZW5ndGgpIHtcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aCA8IDAgPyAwIDogY2hlY2tlZChsZW5ndGgpIHwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHRoYXRbaV0gPSAwXG4gICAgfVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21TdHJpbmcgKHRoYXQsIHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBlbmNvZGluZyAhPT0gJ3N0cmluZycgfHwgZW5jb2RpbmcgPT09ICcnKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIC8vIEFzc3VtcHRpb246IGJ5dGVMZW5ndGgoKSByZXR1cm4gdmFsdWUgaXMgYWx3YXlzIDwga01heExlbmd0aC5cbiAgdmFyIGxlbmd0aCA9IGJ5dGVMZW5ndGgoc3RyaW5nLCBlbmNvZGluZykgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG5cbiAgdGhhdC53cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihvYmplY3QpKSByZXR1cm4gZnJvbUJ1ZmZlcih0aGF0LCBvYmplY3QpXG5cbiAgaWYgKGlzQXJyYXkob2JqZWN0KSkgcmV0dXJuIGZyb21BcnJheSh0aGF0LCBvYmplY3QpXG5cbiAgaWYgKG9iamVjdCA9PSBudWxsKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignbXVzdCBzdGFydCB3aXRoIG51bWJlciwgYnVmZmVyLCBhcnJheSBvciBzdHJpbmcnKVxuICB9XG5cbiAgaWYgKHR5cGVvZiBBcnJheUJ1ZmZlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAob2JqZWN0LmJ1ZmZlciBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgICByZXR1cm4gZnJvbVR5cGVkQXJyYXkodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgICBpZiAob2JqZWN0IGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICAgIHJldHVybiBmcm9tQXJyYXlCdWZmZXIodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgfVxuXG4gIGlmIChvYmplY3QubGVuZ3RoKSByZXR1cm4gZnJvbUFycmF5TGlrZSh0aGF0LCBvYmplY3QpXG5cbiAgcmV0dXJuIGZyb21Kc29uT2JqZWN0KHRoYXQsIG9iamVjdClcbn1cblxuZnVuY3Rpb24gZnJvbUJ1ZmZlciAodGhhdCwgYnVmZmVyKSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGJ1ZmZlci5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICBidWZmZXIuY29weSh0aGF0LCAwLCAwLCBsZW5ndGgpXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheSAodGhhdCwgYXJyYXkpIHtcbiAgdmFyIGxlbmd0aCA9IGNoZWNrZWQoYXJyYXkubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbi8vIER1cGxpY2F0ZSBvZiBmcm9tQXJyYXkoKSB0byBrZWVwIGZyb21BcnJheSgpIG1vbm9tb3JwaGljLlxuZnVuY3Rpb24gZnJvbVR5cGVkQXJyYXkgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIC8vIFRydW5jYXRpbmcgdGhlIGVsZW1lbnRzIGlzIHByb2JhYmx5IG5vdCB3aGF0IHBlb3BsZSBleHBlY3QgZnJvbSB0eXBlZFxuICAvLyBhcnJheXMgd2l0aCBCWVRFU19QRVJfRUxFTUVOVCA+IDEgYnV0IGl0J3MgY29tcGF0aWJsZSB3aXRoIHRoZSBiZWhhdmlvclxuICAvLyBvZiB0aGUgb2xkIEJ1ZmZlciBjb25zdHJ1Y3Rvci5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUJ1ZmZlciAodGhhdCwgYXJyYXkpIHtcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgYXJyYXkuYnl0ZUxlbmd0aFxuICAgIHRoYXQgPSBCdWZmZXIuX2F1Z21lbnQobmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0ID0gZnJvbVR5cGVkQXJyYXkodGhhdCwgbmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUxpa2UgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vLyBEZXNlcmlhbGl6ZSB7IHR5cGU6ICdCdWZmZXInLCBkYXRhOiBbMSwyLDMsLi4uXSB9IGludG8gYSBCdWZmZXIgb2JqZWN0LlxuLy8gUmV0dXJucyBhIHplcm8tbGVuZ3RoIGJ1ZmZlciBmb3IgaW5wdXRzIHRoYXQgZG9uJ3QgY29uZm9ybSB0byB0aGUgc3BlYy5cbmZ1bmN0aW9uIGZyb21Kc29uT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgdmFyIGFycmF5XG4gIHZhciBsZW5ndGggPSAwXG5cbiAgaWYgKG9iamVjdC50eXBlID09PSAnQnVmZmVyJyAmJiBpc0FycmF5KG9iamVjdC5kYXRhKSkge1xuICAgIGFycmF5ID0gb2JqZWN0LmRhdGFcbiAgICBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIH1cbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gIEJ1ZmZlci5wcm90b3R5cGUuX19wcm90b19fID0gVWludDhBcnJheS5wcm90b3R5cGVcbiAgQnVmZmVyLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXlcbn1cblxuZnVuY3Rpb24gYWxsb2NhdGUgKHRoYXQsIGxlbmd0aCkge1xuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAvLyBSZXR1cm4gYW4gYXVnbWVudGVkIGBVaW50OEFycmF5YCBpbnN0YW5jZSwgZm9yIGJlc3QgcGVyZm9ybWFuY2VcbiAgICB0aGF0ID0gQnVmZmVyLl9hdWdtZW50KG5ldyBVaW50OEFycmF5KGxlbmd0aCkpXG4gICAgdGhhdC5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgLy8gRmFsbGJhY2s6IFJldHVybiBhbiBvYmplY3QgaW5zdGFuY2Ugb2YgdGhlIEJ1ZmZlciBjbGFzc1xuICAgIHRoYXQubGVuZ3RoID0gbGVuZ3RoXG4gICAgdGhhdC5faXNCdWZmZXIgPSB0cnVlXG4gIH1cblxuICB2YXIgZnJvbVBvb2wgPSBsZW5ndGggIT09IDAgJiYgbGVuZ3RoIDw9IEJ1ZmZlci5wb29sU2l6ZSA+Pj4gMVxuICBpZiAoZnJvbVBvb2wpIHRoYXQucGFyZW50ID0gcm9vdFBhcmVudFxuXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGNoZWNrZWQgKGxlbmd0aCkge1xuICAvLyBOb3RlOiBjYW5ub3QgdXNlIGBsZW5ndGggPCBrTWF4TGVuZ3RoYCBoZXJlIGJlY2F1c2UgdGhhdCBmYWlscyB3aGVuXG4gIC8vIGxlbmd0aCBpcyBOYU4gKHdoaWNoIGlzIG90aGVyd2lzZSBjb2VyY2VkIHRvIHplcm8uKVxuICBpZiAobGVuZ3RoID49IGtNYXhMZW5ndGgoKSkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIGFsbG9jYXRlIEJ1ZmZlciBsYXJnZXIgdGhhbiBtYXhpbXVtICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICdzaXplOiAweCcgKyBrTWF4TGVuZ3RoKCkudG9TdHJpbmcoMTYpICsgJyBieXRlcycpXG4gIH1cbiAgcmV0dXJuIGxlbmd0aCB8IDBcbn1cblxuZnVuY3Rpb24gU2xvd0J1ZmZlciAoc3ViamVjdCwgZW5jb2RpbmcpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFNsb3dCdWZmZXIpKSByZXR1cm4gbmV3IFNsb3dCdWZmZXIoc3ViamVjdCwgZW5jb2RpbmcpXG5cbiAgdmFyIGJ1ZiA9IG5ldyBCdWZmZXIoc3ViamVjdCwgZW5jb2RpbmcpXG4gIGRlbGV0ZSBidWYucGFyZW50XG4gIHJldHVybiBidWZcbn1cblxuQnVmZmVyLmlzQnVmZmVyID0gZnVuY3Rpb24gaXNCdWZmZXIgKGIpIHtcbiAgcmV0dXJuICEhKGIgIT0gbnVsbCAmJiBiLl9pc0J1ZmZlcilcbn1cblxuQnVmZmVyLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChhLCBiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGEpIHx8ICFCdWZmZXIuaXNCdWZmZXIoYikpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudHMgbXVzdCBiZSBCdWZmZXJzJylcbiAgfVxuXG4gIGlmIChhID09PSBiKSByZXR1cm4gMFxuXG4gIHZhciB4ID0gYS5sZW5ndGhcbiAgdmFyIHkgPSBiLmxlbmd0aFxuXG4gIHZhciBpID0gMFxuICB2YXIgbGVuID0gTWF0aC5taW4oeCwgeSlcbiAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICBpZiAoYVtpXSAhPT0gYltpXSkgYnJlYWtcblxuICAgICsraVxuICB9XG5cbiAgaWYgKGkgIT09IGxlbikge1xuICAgIHggPSBhW2ldXG4gICAgeSA9IGJbaV1cbiAgfVxuXG4gIGlmICh4IDwgeSkgcmV0dXJuIC0xXG4gIGlmICh5IDwgeCkgcmV0dXJuIDFcbiAgcmV0dXJuIDBcbn1cblxuQnVmZmVyLmlzRW5jb2RpbmcgPSBmdW5jdGlvbiBpc0VuY29kaW5nIChlbmNvZGluZykge1xuICBzd2l0Y2ggKFN0cmluZyhlbmNvZGluZykudG9Mb3dlckNhc2UoKSkge1xuICAgIGNhc2UgJ2hleCc6XG4gICAgY2FzZSAndXRmOCc6XG4gICAgY2FzZSAndXRmLTgnOlxuICAgIGNhc2UgJ2FzY2lpJzpcbiAgICBjYXNlICdiaW5hcnknOlxuICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgY2FzZSAncmF3JzpcbiAgICBjYXNlICd1Y3MyJzpcbiAgICBjYXNlICd1Y3MtMic6XG4gICAgY2FzZSAndXRmMTZsZSc6XG4gICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgcmV0dXJuIHRydWVcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuQnVmZmVyLmNvbmNhdCA9IGZ1bmN0aW9uIGNvbmNhdCAobGlzdCwgbGVuZ3RoKSB7XG4gIGlmICghaXNBcnJheShsaXN0KSkgdGhyb3cgbmV3IFR5cGVFcnJvcignbGlzdCBhcmd1bWVudCBtdXN0IGJlIGFuIEFycmF5IG9mIEJ1ZmZlcnMuJylcblxuICBpZiAobGlzdC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcigwKVxuICB9XG5cbiAgdmFyIGlcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbGVuZ3RoID0gMFxuICAgIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBsZW5ndGggKz0gbGlzdFtpXS5sZW5ndGhcbiAgICB9XG4gIH1cblxuICB2YXIgYnVmID0gbmV3IEJ1ZmZlcihsZW5ndGgpXG4gIHZhciBwb3MgPSAwXG4gIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGl0ZW0gPSBsaXN0W2ldXG4gICAgaXRlbS5jb3B5KGJ1ZiwgcG9zKVxuICAgIHBvcyArPSBpdGVtLmxlbmd0aFxuICB9XG4gIHJldHVybiBidWZcbn1cblxuZnVuY3Rpb24gYnl0ZUxlbmd0aCAoc3RyaW5nLCBlbmNvZGluZykge1xuICBpZiAodHlwZW9mIHN0cmluZyAhPT0gJ3N0cmluZycpIHN0cmluZyA9ICcnICsgc3RyaW5nXG5cbiAgdmFyIGxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKGxlbiA9PT0gMCkgcmV0dXJuIDBcblxuICAvLyBVc2UgYSBmb3IgbG9vcCB0byBhdm9pZCByZWN1cnNpb25cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAvLyBEZXByZWNhdGVkXG4gICAgICBjYXNlICdyYXcnOlxuICAgICAgY2FzZSAncmF3cyc6XG4gICAgICAgIHJldHVybiBsZW5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGhcbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiBsZW4gKiAyXG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gbGVuID4+PiAxXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICByZXR1cm4gYmFzZTY0VG9CeXRlcyhzdHJpbmcpLmxlbmd0aFxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSByZXR1cm4gdXRmOFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGggLy8gYXNzdW1lIHV0ZjhcbiAgICAgICAgZW5jb2RpbmcgPSAoJycgKyBlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cbkJ1ZmZlci5ieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aFxuXG4vLyBwcmUtc2V0IGZvciB2YWx1ZXMgdGhhdCBtYXkgZXhpc3QgaW4gdGhlIGZ1dHVyZVxuQnVmZmVyLnByb3RvdHlwZS5sZW5ndGggPSB1bmRlZmluZWRcbkJ1ZmZlci5wcm90b3R5cGUucGFyZW50ID0gdW5kZWZpbmVkXG5cbmZ1bmN0aW9uIHNsb3dUb1N0cmluZyAoZW5jb2RpbmcsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcblxuICBzdGFydCA9IHN0YXJ0IHwgMFxuICBlbmQgPSBlbmQgPT09IHVuZGVmaW5lZCB8fCBlbmQgPT09IEluZmluaXR5ID8gdGhpcy5sZW5ndGggOiBlbmQgfCAwXG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcbiAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKGVuZCA8PSBzdGFydCkgcmV0dXJuICcnXG5cbiAgd2hpbGUgKHRydWUpIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1dGYxNmxlU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKGVuY29kaW5nICsgJycpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9TdHJpbmcgPSBmdW5jdGlvbiB0b1N0cmluZyAoKSB7XG4gIHZhciBsZW5ndGggPSB0aGlzLmxlbmd0aCB8IDBcbiAgaWYgKGxlbmd0aCA9PT0gMCkgcmV0dXJuICcnXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSByZXR1cm4gdXRmOFNsaWNlKHRoaXMsIDAsIGxlbmd0aClcbiAgcmV0dXJuIHNsb3dUb1N0cmluZy5hcHBseSh0aGlzLCBhcmd1bWVudHMpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24gZXF1YWxzIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiB0cnVlXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKSA9PT0gMFxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluc3BlY3QgPSBmdW5jdGlvbiBpbnNwZWN0ICgpIHtcbiAgdmFyIHN0ciA9ICcnXG4gIHZhciBtYXggPSBleHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTXG4gIGlmICh0aGlzLmxlbmd0aCA+IDApIHtcbiAgICBzdHIgPSB0aGlzLnRvU3RyaW5nKCdoZXgnLCAwLCBtYXgpLm1hdGNoKC8uezJ9L2cpLmpvaW4oJyAnKVxuICAgIGlmICh0aGlzLmxlbmd0aCA+IG1heCkgc3RyICs9ICcgLi4uICdcbiAgfVxuICByZXR1cm4gJzxCdWZmZXIgJyArIHN0ciArICc+J1xufVxuXG5CdWZmZXIucHJvdG90eXBlLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiAwXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluZGV4T2YgPSBmdW5jdGlvbiBpbmRleE9mICh2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgaWYgKGJ5dGVPZmZzZXQgPiAweDdmZmZmZmZmKSBieXRlT2Zmc2V0ID0gMHg3ZmZmZmZmZlxuICBlbHNlIGlmIChieXRlT2Zmc2V0IDwgLTB4ODAwMDAwMDApIGJ5dGVPZmZzZXQgPSAtMHg4MDAwMDAwMFxuICBieXRlT2Zmc2V0ID4+PSAwXG5cbiAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gLTFcbiAgaWYgKGJ5dGVPZmZzZXQgPj0gdGhpcy5sZW5ndGgpIHJldHVybiAtMVxuXG4gIC8vIE5lZ2F0aXZlIG9mZnNldHMgc3RhcnQgZnJvbSB0aGUgZW5kIG9mIHRoZSBidWZmZXJcbiAgaWYgKGJ5dGVPZmZzZXQgPCAwKSBieXRlT2Zmc2V0ID0gTWF0aC5tYXgodGhpcy5sZW5ndGggKyBieXRlT2Zmc2V0LCAwKVxuXG4gIGlmICh0eXBlb2YgdmFsID09PSAnc3RyaW5nJykge1xuICAgIGlmICh2YWwubGVuZ3RoID09PSAwKSByZXR1cm4gLTEgLy8gc3BlY2lhbCBjYXNlOiBsb29raW5nIGZvciBlbXB0eSBzdHJpbmcgYWx3YXlzIGZhaWxzXG4gICAgcmV0dXJuIFN0cmluZy5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAoQnVmZmVyLmlzQnVmZmVyKHZhbCkpIHtcbiAgICByZXR1cm4gYXJyYXlJbmRleE9mKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ251bWJlcicpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQgJiYgVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgcmV0dXJuIFVpbnQ4QXJyYXkucHJvdG90eXBlLmluZGV4T2YuY2FsbCh0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gICAgfVxuICAgIHJldHVybiBhcnJheUluZGV4T2YodGhpcywgWyB2YWwgXSwgYnl0ZU9mZnNldClcbiAgfVxuXG4gIGZ1bmN0aW9uIGFycmF5SW5kZXhPZiAoYXJyLCB2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgICB2YXIgZm91bmRJbmRleCA9IC0xXG4gICAgZm9yICh2YXIgaSA9IDA7IGJ5dGVPZmZzZXQgKyBpIDwgYXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoYXJyW2J5dGVPZmZzZXQgKyBpXSA9PT0gdmFsW2ZvdW5kSW5kZXggPT09IC0xID8gMCA6IGkgLSBmb3VuZEluZGV4XSkge1xuICAgICAgICBpZiAoZm91bmRJbmRleCA9PT0gLTEpIGZvdW5kSW5kZXggPSBpXG4gICAgICAgIGlmIChpIC0gZm91bmRJbmRleCArIDEgPT09IHZhbC5sZW5ndGgpIHJldHVybiBieXRlT2Zmc2V0ICsgZm91bmRJbmRleFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZm91bmRJbmRleCA9IC0xXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAtMVxuICB9XG5cbiAgdGhyb3cgbmV3IFR5cGVFcnJvcigndmFsIG11c3QgYmUgc3RyaW5nLCBudW1iZXIgb3IgQnVmZmVyJylcbn1cblxuLy8gYGdldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5nZXQgPSBmdW5jdGlvbiBnZXQgKG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLmdldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMucmVhZFVJbnQ4KG9mZnNldClcbn1cblxuLy8gYHNldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5zZXQgPSBmdW5jdGlvbiBzZXQgKHYsIG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLnNldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMud3JpdGVVSW50OCh2LCBvZmZzZXQpXG59XG5cbmZ1bmN0aW9uIGhleFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgb2Zmc2V0ID0gTnVtYmVyKG9mZnNldCkgfHwgMFxuICB2YXIgcmVtYWluaW5nID0gYnVmLmxlbmd0aCAtIG9mZnNldFxuICBpZiAoIWxlbmd0aCkge1xuICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICB9IGVsc2Uge1xuICAgIGxlbmd0aCA9IE51bWJlcihsZW5ndGgpXG4gICAgaWYgKGxlbmd0aCA+IHJlbWFpbmluZykge1xuICAgICAgbGVuZ3RoID0gcmVtYWluaW5nXG4gICAgfVxuICB9XG5cbiAgLy8gbXVzdCBiZSBhbiBldmVuIG51bWJlciBvZiBkaWdpdHNcbiAgdmFyIHN0ckxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKHN0ckxlbiAlIDIgIT09IDApIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcblxuICBpZiAobGVuZ3RoID4gc3RyTGVuIC8gMikge1xuICAgIGxlbmd0aCA9IHN0ckxlbiAvIDJcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHBhcnNlZCA9IHBhcnNlSW50KHN0cmluZy5zdWJzdHIoaSAqIDIsIDIpLCAxNilcbiAgICBpZiAoaXNOYU4ocGFyc2VkKSkgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGhleCBzdHJpbmcnKVxuICAgIGJ1ZltvZmZzZXQgKyBpXSA9IHBhcnNlZFxuICB9XG4gIHJldHVybiBpXG59XG5cbmZ1bmN0aW9uIHV0ZjhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKHV0ZjhUb0J5dGVzKHN0cmluZywgYnVmLmxlbmd0aCAtIG9mZnNldCksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGFzY2lpV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcihhc2NpaVRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYmluYXJ5V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYXNjaWlXcml0ZShidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGJhc2U2NFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIoYmFzZTY0VG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiB1Y3MyV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcih1dGYxNmxlVG9CeXRlcyhzdHJpbmcsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlID0gZnVuY3Rpb24gd3JpdGUgKHN0cmluZywgb2Zmc2V0LCBsZW5ndGgsIGVuY29kaW5nKSB7XG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcpXG4gIGlmIChvZmZzZXQgPT09IHVuZGVmaW5lZCkge1xuICAgIGVuY29kaW5nID0gJ3V0ZjgnXG4gICAgbGVuZ3RoID0gdGhpcy5sZW5ndGhcbiAgICBvZmZzZXQgPSAwXG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICB9IGVsc2UgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkICYmIHR5cGVvZiBvZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgZW5jb2RpbmcgPSBvZmZzZXRcbiAgICBsZW5ndGggPSB0aGlzLmxlbmd0aFxuICAgIG9mZnNldCA9IDBcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZywgb2Zmc2V0WywgbGVuZ3RoXVssIGVuY29kaW5nXSlcbiAgfSBlbHNlIGlmIChpc0Zpbml0ZShvZmZzZXQpKSB7XG4gICAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICAgIGlmIChpc0Zpbml0ZShsZW5ndGgpKSB7XG4gICAgICBsZW5ndGggPSBsZW5ndGggfCAwXG4gICAgICBpZiAoZW5jb2RpbmcgPT09IHVuZGVmaW5lZCkgZW5jb2RpbmcgPSAndXRmOCdcbiAgICB9IGVsc2Uge1xuICAgICAgZW5jb2RpbmcgPSBsZW5ndGhcbiAgICAgIGxlbmd0aCA9IHVuZGVmaW5lZFxuICAgIH1cbiAgLy8gbGVnYWN5IHdyaXRlKHN0cmluZywgZW5jb2RpbmcsIG9mZnNldCwgbGVuZ3RoKSAtIHJlbW92ZSBpbiB2MC4xM1xuICB9IGVsc2Uge1xuICAgIHZhciBzd2FwID0gZW5jb2RpbmdcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIG9mZnNldCA9IGxlbmd0aCB8IDBcbiAgICBsZW5ndGggPSBzd2FwXG4gIH1cblxuICB2YXIgcmVtYWluaW5nID0gdGhpcy5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkIHx8IGxlbmd0aCA+IHJlbWFpbmluZykgbGVuZ3RoID0gcmVtYWluaW5nXG5cbiAgaWYgKChzdHJpbmcubGVuZ3RoID4gMCAmJiAobGVuZ3RoIDwgMCB8fCBvZmZzZXQgPCAwKSkgfHwgb2Zmc2V0ID4gdGhpcy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignYXR0ZW1wdCB0byB3cml0ZSBvdXRzaWRlIGJ1ZmZlciBib3VuZHMnKVxuICB9XG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcblxuICB2YXIgbG93ZXJlZENhc2UgPSBmYWxzZVxuICBmb3IgKDs7KSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGhleFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgICAgcmV0dXJuIGFzY2lpV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgICAgcmV0dXJuIGJpbmFyeVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIC8vIFdhcm5pbmc6IG1heExlbmd0aCBub3QgdGFrZW4gaW50byBhY2NvdW50IGluIGJhc2U2NFdyaXRlXG4gICAgICAgIHJldHVybiBiYXNlNjRXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gdWNzMldyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgICAgICBlbmNvZGluZyA9ICgnJyArIGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvSlNPTiA9IGZ1bmN0aW9uIHRvSlNPTiAoKSB7XG4gIHJldHVybiB7XG4gICAgdHlwZTogJ0J1ZmZlcicsXG4gICAgZGF0YTogQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodGhpcy5fYXJyIHx8IHRoaXMsIDApXG4gIH1cbn1cblxuZnVuY3Rpb24gYmFzZTY0U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICBpZiAoc3RhcnQgPT09IDAgJiYgZW5kID09PSBidWYubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGJhc2U2NC5mcm9tQnl0ZUFycmF5KGJ1ZilcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmLnNsaWNlKHN0YXJ0LCBlbmQpKVxuICB9XG59XG5cbmZ1bmN0aW9uIHV0ZjhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcbiAgdmFyIHJlcyA9IFtdXG5cbiAgdmFyIGkgPSBzdGFydFxuICB3aGlsZSAoaSA8IGVuZCkge1xuICAgIHZhciBmaXJzdEJ5dGUgPSBidWZbaV1cbiAgICB2YXIgY29kZVBvaW50ID0gbnVsbFxuICAgIHZhciBieXRlc1BlclNlcXVlbmNlID0gKGZpcnN0Qnl0ZSA+IDB4RUYpID8gNFxuICAgICAgOiAoZmlyc3RCeXRlID4gMHhERikgPyAzXG4gICAgICA6IChmaXJzdEJ5dGUgPiAweEJGKSA/IDJcbiAgICAgIDogMVxuXG4gICAgaWYgKGkgKyBieXRlc1BlclNlcXVlbmNlIDw9IGVuZCkge1xuICAgICAgdmFyIHNlY29uZEJ5dGUsIHRoaXJkQnl0ZSwgZm91cnRoQnl0ZSwgdGVtcENvZGVQb2ludFxuXG4gICAgICBzd2l0Y2ggKGJ5dGVzUGVyU2VxdWVuY2UpIHtcbiAgICAgICAgY2FzZSAxOlxuICAgICAgICAgIGlmIChmaXJzdEJ5dGUgPCAweDgwKSB7XG4gICAgICAgICAgICBjb2RlUG9pbnQgPSBmaXJzdEJ5dGVcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHgxRikgPDwgMHg2IHwgKHNlY29uZEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweDdGKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwICYmICh0aGlyZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4QyB8IChzZWNvbmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKHRoaXJkQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0ZGICYmICh0ZW1wQ29kZVBvaW50IDwgMHhEODAwIHx8IHRlbXBDb2RlUG9pbnQgPiAweERGRkYpKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSA0OlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGZvdXJ0aEJ5dGUgPSBidWZbaSArIDNdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwICYmIChmb3VydGhCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHhGKSA8PCAweDEyIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweEMgfCAodGhpcmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKGZvdXJ0aEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweEZGRkYgJiYgdGVtcENvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGNvZGVQb2ludCA9PT0gbnVsbCkge1xuICAgICAgLy8gd2UgZGlkIG5vdCBnZW5lcmF0ZSBhIHZhbGlkIGNvZGVQb2ludCBzbyBpbnNlcnQgYVxuICAgICAgLy8gcmVwbGFjZW1lbnQgY2hhciAoVStGRkZEKSBhbmQgYWR2YW5jZSBvbmx5IDEgYnl0ZVxuICAgICAgY29kZVBvaW50ID0gMHhGRkZEXG4gICAgICBieXRlc1BlclNlcXVlbmNlID0gMVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50ID4gMHhGRkZGKSB7XG4gICAgICAvLyBlbmNvZGUgdG8gdXRmMTYgKHN1cnJvZ2F0ZSBwYWlyIGRhbmNlKVxuICAgICAgY29kZVBvaW50IC09IDB4MTAwMDBcbiAgICAgIHJlcy5wdXNoKGNvZGVQb2ludCA+Pj4gMTAgJiAweDNGRiB8IDB4RDgwMClcbiAgICAgIGNvZGVQb2ludCA9IDB4REMwMCB8IGNvZGVQb2ludCAmIDB4M0ZGXG4gICAgfVxuXG4gICAgcmVzLnB1c2goY29kZVBvaW50KVxuICAgIGkgKz0gYnl0ZXNQZXJTZXF1ZW5jZVxuICB9XG5cbiAgcmV0dXJuIGRlY29kZUNvZGVQb2ludHNBcnJheShyZXMpXG59XG5cbi8vIEJhc2VkIG9uIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzIyNzQ3MjcyLzY4MDc0MiwgdGhlIGJyb3dzZXIgd2l0aFxuLy8gdGhlIGxvd2VzdCBsaW1pdCBpcyBDaHJvbWUsIHdpdGggMHgxMDAwMCBhcmdzLlxuLy8gV2UgZ28gMSBtYWduaXR1ZGUgbGVzcywgZm9yIHNhZmV0eVxudmFyIE1BWF9BUkdVTUVOVFNfTEVOR1RIID0gMHgxMDAwXG5cbmZ1bmN0aW9uIGRlY29kZUNvZGVQb2ludHNBcnJheSAoY29kZVBvaW50cykge1xuICB2YXIgbGVuID0gY29kZVBvaW50cy5sZW5ndGhcbiAgaWYgKGxlbiA8PSBNQVhfQVJHVU1FTlRTX0xFTkdUSCkge1xuICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFN0cmluZywgY29kZVBvaW50cykgLy8gYXZvaWQgZXh0cmEgc2xpY2UoKVxuICB9XG5cbiAgLy8gRGVjb2RlIGluIGNodW5rcyB0byBhdm9pZCBcImNhbGwgc3RhY2sgc2l6ZSBleGNlZWRlZFwiLlxuICB2YXIgcmVzID0gJydcbiAgdmFyIGkgPSAwXG4gIHdoaWxlIChpIDwgbGVuKSB7XG4gICAgcmVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoXG4gICAgICBTdHJpbmcsXG4gICAgICBjb2RlUG9pbnRzLnNsaWNlKGksIGkgKz0gTUFYX0FSR1VNRU5UU19MRU5HVEgpXG4gICAgKVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0gJiAweDdGKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gYmluYXJ5U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgcmV0ID0gJydcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgcmV0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnVmW2ldKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gaGV4U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gYnVmLmxlbmd0aFxuXG4gIGlmICghc3RhcnQgfHwgc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgfHwgZW5kIDwgMCB8fCBlbmQgPiBsZW4pIGVuZCA9IGxlblxuXG4gIHZhciBvdXQgPSAnJ1xuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIG91dCArPSB0b0hleChidWZbaV0pXG4gIH1cbiAgcmV0dXJuIG91dFxufVxuXG5mdW5jdGlvbiB1dGYxNmxlU2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgYnl0ZXMgPSBidWYuc2xpY2Uoc3RhcnQsIGVuZClcbiAgdmFyIHJlcyA9ICcnXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShieXRlc1tpXSArIGJ5dGVzW2kgKyAxXSAqIDI1NilcbiAgfVxuICByZXR1cm4gcmVzXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuc2xpY2UgPSBmdW5jdGlvbiBzbGljZSAoc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gdGhpcy5sZW5ndGhcbiAgc3RhcnQgPSB+fnN0YXJ0XG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkID8gbGVuIDogfn5lbmRcblxuICBpZiAoc3RhcnQgPCAwKSB7XG4gICAgc3RhcnQgKz0gbGVuXG4gICAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIH0gZWxzZSBpZiAoc3RhcnQgPiBsZW4pIHtcbiAgICBzdGFydCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IDApIHtcbiAgICBlbmQgKz0gbGVuXG4gICAgaWYgKGVuZCA8IDApIGVuZCA9IDBcbiAgfSBlbHNlIGlmIChlbmQgPiBsZW4pIHtcbiAgICBlbmQgPSBsZW5cbiAgfVxuXG4gIGlmIChlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICB2YXIgbmV3QnVmXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIG5ld0J1ZiA9IEJ1ZmZlci5fYXVnbWVudCh0aGlzLnN1YmFycmF5KHN0YXJ0LCBlbmQpKVxuICB9IGVsc2Uge1xuICAgIHZhciBzbGljZUxlbiA9IGVuZCAtIHN0YXJ0XG4gICAgbmV3QnVmID0gbmV3IEJ1ZmZlcihzbGljZUxlbiwgdW5kZWZpbmVkKVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2xpY2VMZW47IGkrKykge1xuICAgICAgbmV3QnVmW2ldID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9XG5cbiAgaWYgKG5ld0J1Zi5sZW5ndGgpIG5ld0J1Zi5wYXJlbnQgPSB0aGlzLnBhcmVudCB8fCB0aGlzXG5cbiAgcmV0dXJuIG5ld0J1ZlxufVxuXG4vKlxuICogTmVlZCB0byBtYWtlIHN1cmUgdGhhdCBidWZmZXIgaXNuJ3QgdHJ5aW5nIHRvIHdyaXRlIG91dCBvZiBib3VuZHMuXG4gKi9cbmZ1bmN0aW9uIGNoZWNrT2Zmc2V0IChvZmZzZXQsIGV4dCwgbGVuZ3RoKSB7XG4gIGlmICgob2Zmc2V0ICUgMSkgIT09IDAgfHwgb2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ29mZnNldCBpcyBub3QgdWludCcpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBsZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdUcnlpbmcgdG8gYWNjZXNzIGJleW9uZCBidWZmZXIgbGVuZ3RoJylcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludExFID0gZnVuY3Rpb24gcmVhZFVJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludEJFID0gZnVuY3Rpb24gcmVhZFVJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcbiAgfVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIC0tYnl0ZUxlbmd0aF1cbiAgdmFyIG11bCA9IDFcbiAgd2hpbGUgKGJ5dGVMZW5ndGggPiAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50OCA9IGZ1bmN0aW9uIHJlYWRVSW50OCAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDEsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gdGhpc1tvZmZzZXRdXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkxFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MTZCRSA9IGZ1bmN0aW9uIHJlYWRVSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCA4KSB8IHRoaXNbb2Zmc2V0ICsgMV1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyTEUgPSBmdW5jdGlvbiByZWFkVUludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKCh0aGlzW29mZnNldF0pIHxcbiAgICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAgICh0aGlzW29mZnNldCArIDJdIDw8IDE2KSkgK1xuICAgICAgKHRoaXNbb2Zmc2V0ICsgM10gKiAweDEwMDAwMDApXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQzMkJFID0gZnVuY3Rpb24gcmVhZFVJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gKiAweDEwMDAwMDApICtcbiAgICAoKHRoaXNbb2Zmc2V0ICsgMV0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCA4KSB8XG4gICAgdGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50TEUgPSBmdW5jdGlvbiByZWFkSW50TEUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIGldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50QkUgPSBmdW5jdGlvbiByZWFkSW50QkUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgaSA9IGJ5dGVMZW5ndGhcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1pXVxuICB3aGlsZSAoaSA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50OCA9IGZ1bmN0aW9uIHJlYWRJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIGlmICghKHRoaXNbb2Zmc2V0XSAmIDB4ODApKSByZXR1cm4gKHRoaXNbb2Zmc2V0XSlcbiAgcmV0dXJuICgoMHhmZiAtIHRoaXNbb2Zmc2V0XSArIDEpICogLTEpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2TEUgPSBmdW5jdGlvbiByZWFkSW50MTZMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdIHwgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQxNkJFID0gZnVuY3Rpb24gcmVhZEludDE2QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgMV0gfCAodGhpc1tvZmZzZXRdIDw8IDgpXG4gIHJldHVybiAodmFsICYgMHg4MDAwKSA/IHZhbCB8IDB4RkZGRjAwMDAgOiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0pIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSA8PCAyNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJCRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gPDwgMjQpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRMRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdExFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRCRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdEJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCBmYWxzZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUxFID0gZnVuY3Rpb24gcmVhZERvdWJsZUxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgOCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCA1MiwgOClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlQkUgPSBmdW5jdGlvbiByZWFkRG91YmxlQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCA1MiwgOClcbn1cblxuZnVuY3Rpb24gY2hlY2tJbnQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihidWYpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdidWZmZXIgbXVzdCBiZSBhIEJ1ZmZlciBpbnN0YW5jZScpXG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3ZhbHVlIGlzIG91dCBvZiBib3VuZHMnKVxuICBpZiAob2Zmc2V0ICsgZXh0ID4gYnVmLmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB0aGlzW29mZnNldF0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50QkUgPSBmdW5jdGlvbiB3cml0ZVVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aCAtIDFcbiAgdmFyIG11bCA9IDFcbiAgdGhpc1tvZmZzZXQgKyBpXSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoLS1pID49IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50OCA9IGZ1bmN0aW9uIHdyaXRlVUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHhmZiwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkgdmFsdWUgPSBNYXRoLmZsb29yKHZhbHVlKVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQxNiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmYgKyB2YWx1ZSArIDFcbiAgZm9yICh2YXIgaSA9IDAsIGogPSBNYXRoLm1pbihidWYubGVuZ3RoIC0gb2Zmc2V0LCAyKTsgaSA8IGo7IGkrKykge1xuICAgIGJ1ZltvZmZzZXQgKyBpXSA9ICh2YWx1ZSAmICgweGZmIDw8ICg4ICogKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkpKSkgPj4+XG4gICAgICAobGl0dGxlRW5kaWFuID8gaSA6IDEgLSBpKSAqIDhcbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDE2TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4ZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQzMiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgNCk7IGkgPCBqOyBpKyspIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgPj4+IChsaXR0bGVFbmRpYW4gPyBpIDogMyAtIGkpICogOCkgJiAweGZmXG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDMyQkUgPSBmdW5jdGlvbiB3cml0ZVVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4ZmZmZmZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50TEUgPSBmdW5jdGlvbiB3cml0ZUludExFICh2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbGltaXQgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCAtIDEpXG5cbiAgICBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBsaW1pdCAtIDEsIC1saW1pdClcbiAgfVxuXG4gIHZhciBpID0gMFxuICB2YXIgbXVsID0gMVxuICB2YXIgc3ViID0gdmFsdWUgPCAwID8gMSA6IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludEJFID0gZnVuY3Rpb24gd3JpdGVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSB2YWx1ZSA8IDAgPyAxIDogMFxuICB0aGlzW29mZnNldCArIGldID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgtLWkgPj0gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAoKHZhbHVlIC8gbXVsKSA+PiAwKSAtIHN1YiAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQ4ID0gZnVuY3Rpb24gd3JpdGVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4N2YsIC0weDgwKVxuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB2YWx1ZSA9IE1hdGguZmxvb3IodmFsdWUpXG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZiArIHZhbHVlICsgMVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MTZMRSA9IGZ1bmN0aW9uIHdyaXRlSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweDdmZmYsIC0weDgwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MzJCRSA9IGZ1bmN0aW9uIHdyaXRlSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweDdmZmZmZmZmLCAtMHg4MDAwMDAwMClcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5mdW5jdGlvbiBjaGVja0lFRUU3NTQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAodmFsdWUgPiBtYXggfHwgdmFsdWUgPCBtaW4pIHRocm93IG5ldyBSYW5nZUVycm9yKCd2YWx1ZSBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxuICBpZiAob2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRmxvYXQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgNCwgMy40MDI4MjM0NjYzODUyODg2ZSszOCwgLTMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgMjMsIDQpXG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdExFID0gZnVuY3Rpb24gd3JpdGVGbG9hdExFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUZsb2F0QkUgPSBmdW5jdGlvbiB3cml0ZUZsb2F0QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZUZsb2F0KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuZnVuY3Rpb24gd3JpdGVEb3VibGUgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgOCwgMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgsIC0xLjc5NzY5MzEzNDg2MjMxNTdFKzMwOClcbiAgfVxuICBpZWVlNzU0LndyaXRlKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCA1MiwgOClcbiAgcmV0dXJuIG9mZnNldCArIDhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUxFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUsIG5vQXNzZXJ0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRG91YmxlQkUgPSBmdW5jdGlvbiB3cml0ZURvdWJsZUJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVEb3VibGUodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UsIG5vQXNzZXJ0KVxufVxuXG4vLyBjb3B5KHRhcmdldEJ1ZmZlciwgdGFyZ2V0U3RhcnQ9MCwgc291cmNlU3RhcnQ9MCwgc291cmNlRW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmNvcHkgPSBmdW5jdGlvbiBjb3B5ICh0YXJnZXQsIHRhcmdldFN0YXJ0LCBzdGFydCwgZW5kKSB7XG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCAmJiBlbmQgIT09IDApIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmICh0YXJnZXRTdGFydCA+PSB0YXJnZXQubGVuZ3RoKSB0YXJnZXRTdGFydCA9IHRhcmdldC5sZW5ndGhcbiAgaWYgKCF0YXJnZXRTdGFydCkgdGFyZ2V0U3RhcnQgPSAwXG4gIGlmIChlbmQgPiAwICYmIGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIC8vIENvcHkgMCBieXRlczsgd2UncmUgZG9uZVxuICBpZiAoZW5kID09PSBzdGFydCkgcmV0dXJuIDBcbiAgaWYgKHRhcmdldC5sZW5ndGggPT09IDAgfHwgdGhpcy5sZW5ndGggPT09IDApIHJldHVybiAwXG5cbiAgLy8gRmF0YWwgZXJyb3IgY29uZGl0aW9uc1xuICBpZiAodGFyZ2V0U3RhcnQgPCAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3RhcmdldFN0YXJ0IG91dCBvZiBib3VuZHMnKVxuICB9XG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VFbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgLy8gQXJlIHdlIG9vYj9cbiAgaWYgKGVuZCA+IHRoaXMubGVuZ3RoKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0IDwgZW5kIC0gc3RhcnQpIHtcbiAgICBlbmQgPSB0YXJnZXQubGVuZ3RoIC0gdGFyZ2V0U3RhcnQgKyBzdGFydFxuICB9XG5cbiAgdmFyIGxlbiA9IGVuZCAtIHN0YXJ0XG4gIHZhciBpXG5cbiAgaWYgKHRoaXMgPT09IHRhcmdldCAmJiBzdGFydCA8IHRhcmdldFN0YXJ0ICYmIHRhcmdldFN0YXJ0IDwgZW5kKSB7XG4gICAgLy8gZGVzY2VuZGluZyBjb3B5IGZyb20gZW5kXG4gICAgZm9yIChpID0gbGVuIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2UgaWYgKGxlbiA8IDEwMDAgfHwgIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gYXNjZW5kaW5nIGNvcHkgZnJvbSBzdGFydFxuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgdGFyZ2V0W2kgKyB0YXJnZXRTdGFydF0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGFyZ2V0Ll9zZXQodGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLCB0YXJnZXRTdGFydClcbiAgfVxuXG4gIHJldHVybiBsZW5cbn1cblxuLy8gZmlsbCh2YWx1ZSwgc3RhcnQ9MCwgZW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmZpbGwgPSBmdW5jdGlvbiBmaWxsICh2YWx1ZSwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXZhbHVlKSB2YWx1ZSA9IDBcbiAgaWYgKCFzdGFydCkgc3RhcnQgPSAwXG4gIGlmICghZW5kKSBlbmQgPSB0aGlzLmxlbmd0aFxuXG4gIGlmIChlbmQgPCBzdGFydCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2VuZCA8IHN0YXJ0JylcblxuICAvLyBGaWxsIDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVyblxuICBpZiAodGhpcy5sZW5ndGggPT09IDApIHJldHVyblxuXG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDAgfHwgZW5kID4gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdlbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgdmFyIGlcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICBmb3IgKGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgICB0aGlzW2ldID0gdmFsdWVcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFyIGJ5dGVzID0gdXRmOFRvQnl0ZXModmFsdWUudG9TdHJpbmcoKSlcbiAgICB2YXIgbGVuID0gYnl0ZXMubGVuZ3RoXG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdGhpc1tpXSA9IGJ5dGVzW2kgJSBsZW5dXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXNcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IGBBcnJheUJ1ZmZlcmAgd2l0aCB0aGUgKmNvcGllZCogbWVtb3J5IG9mIHRoZSBidWZmZXIgaW5zdGFuY2UuXG4gKiBBZGRlZCBpbiBOb2RlIDAuMTIuIE9ubHkgYXZhaWxhYmxlIGluIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCBBcnJheUJ1ZmZlci5cbiAqL1xuQnVmZmVyLnByb3RvdHlwZS50b0FycmF5QnVmZmVyID0gZnVuY3Rpb24gdG9BcnJheUJ1ZmZlciAoKSB7XG4gIGlmICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAgIHJldHVybiAobmV3IEJ1ZmZlcih0aGlzKSkuYnVmZmVyXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBidWYgPSBuZXcgVWludDhBcnJheSh0aGlzLmxlbmd0aClcbiAgICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBidWYubGVuZ3RoOyBpIDwgbGVuOyBpICs9IDEpIHtcbiAgICAgICAgYnVmW2ldID0gdGhpc1tpXVxuICAgICAgfVxuICAgICAgcmV0dXJuIGJ1Zi5idWZmZXJcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQnVmZmVyLnRvQXJyYXlCdWZmZXIgbm90IHN1cHBvcnRlZCBpbiB0aGlzIGJyb3dzZXInKVxuICB9XG59XG5cbi8vIEhFTFBFUiBGVU5DVElPTlNcbi8vID09PT09PT09PT09PT09PT1cblxudmFyIEJQID0gQnVmZmVyLnByb3RvdHlwZVxuXG4vKipcbiAqIEF1Z21lbnQgYSBVaW50OEFycmF5ICppbnN0YW5jZSogKG5vdCB0aGUgVWludDhBcnJheSBjbGFzcyEpIHdpdGggQnVmZmVyIG1ldGhvZHNcbiAqL1xuQnVmZmVyLl9hdWdtZW50ID0gZnVuY3Rpb24gX2F1Z21lbnQgKGFycikge1xuICBhcnIuY29uc3RydWN0b3IgPSBCdWZmZXJcbiAgYXJyLl9pc0J1ZmZlciA9IHRydWVcblxuICAvLyBzYXZlIHJlZmVyZW5jZSB0byBvcmlnaW5hbCBVaW50OEFycmF5IHNldCBtZXRob2QgYmVmb3JlIG92ZXJ3cml0aW5nXG4gIGFyci5fc2V0ID0gYXJyLnNldFxuXG4gIC8vIGRlcHJlY2F0ZWRcbiAgYXJyLmdldCA9IEJQLmdldFxuICBhcnIuc2V0ID0gQlAuc2V0XG5cbiAgYXJyLndyaXRlID0gQlAud3JpdGVcbiAgYXJyLnRvU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvTG9jYWxlU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvSlNPTiA9IEJQLnRvSlNPTlxuICBhcnIuZXF1YWxzID0gQlAuZXF1YWxzXG4gIGFyci5jb21wYXJlID0gQlAuY29tcGFyZVxuICBhcnIuaW5kZXhPZiA9IEJQLmluZGV4T2ZcbiAgYXJyLmNvcHkgPSBCUC5jb3B5XG4gIGFyci5zbGljZSA9IEJQLnNsaWNlXG4gIGFyci5yZWFkVUludExFID0gQlAucmVhZFVJbnRMRVxuICBhcnIucmVhZFVJbnRCRSA9IEJQLnJlYWRVSW50QkVcbiAgYXJyLnJlYWRVSW50OCA9IEJQLnJlYWRVSW50OFxuICBhcnIucmVhZFVJbnQxNkxFID0gQlAucmVhZFVJbnQxNkxFXG4gIGFyci5yZWFkVUludDE2QkUgPSBCUC5yZWFkVUludDE2QkVcbiAgYXJyLnJlYWRVSW50MzJMRSA9IEJQLnJlYWRVSW50MzJMRVxuICBhcnIucmVhZFVJbnQzMkJFID0gQlAucmVhZFVJbnQzMkJFXG4gIGFyci5yZWFkSW50TEUgPSBCUC5yZWFkSW50TEVcbiAgYXJyLnJlYWRJbnRCRSA9IEJQLnJlYWRJbnRCRVxuICBhcnIucmVhZEludDggPSBCUC5yZWFkSW50OFxuICBhcnIucmVhZEludDE2TEUgPSBCUC5yZWFkSW50MTZMRVxuICBhcnIucmVhZEludDE2QkUgPSBCUC5yZWFkSW50MTZCRVxuICBhcnIucmVhZEludDMyTEUgPSBCUC5yZWFkSW50MzJMRVxuICBhcnIucmVhZEludDMyQkUgPSBCUC5yZWFkSW50MzJCRVxuICBhcnIucmVhZEZsb2F0TEUgPSBCUC5yZWFkRmxvYXRMRVxuICBhcnIucmVhZEZsb2F0QkUgPSBCUC5yZWFkRmxvYXRCRVxuICBhcnIucmVhZERvdWJsZUxFID0gQlAucmVhZERvdWJsZUxFXG4gIGFyci5yZWFkRG91YmxlQkUgPSBCUC5yZWFkRG91YmxlQkVcbiAgYXJyLndyaXRlVUludDggPSBCUC53cml0ZVVJbnQ4XG4gIGFyci53cml0ZVVJbnRMRSA9IEJQLndyaXRlVUludExFXG4gIGFyci53cml0ZVVJbnRCRSA9IEJQLndyaXRlVUludEJFXG4gIGFyci53cml0ZVVJbnQxNkxFID0gQlAud3JpdGVVSW50MTZMRVxuICBhcnIud3JpdGVVSW50MTZCRSA9IEJQLndyaXRlVUludDE2QkVcbiAgYXJyLndyaXRlVUludDMyTEUgPSBCUC53cml0ZVVJbnQzMkxFXG4gIGFyci53cml0ZVVJbnQzMkJFID0gQlAud3JpdGVVSW50MzJCRVxuICBhcnIud3JpdGVJbnRMRSA9IEJQLndyaXRlSW50TEVcbiAgYXJyLndyaXRlSW50QkUgPSBCUC53cml0ZUludEJFXG4gIGFyci53cml0ZUludDggPSBCUC53cml0ZUludDhcbiAgYXJyLndyaXRlSW50MTZMRSA9IEJQLndyaXRlSW50MTZMRVxuICBhcnIud3JpdGVJbnQxNkJFID0gQlAud3JpdGVJbnQxNkJFXG4gIGFyci53cml0ZUludDMyTEUgPSBCUC53cml0ZUludDMyTEVcbiAgYXJyLndyaXRlSW50MzJCRSA9IEJQLndyaXRlSW50MzJCRVxuICBhcnIud3JpdGVGbG9hdExFID0gQlAud3JpdGVGbG9hdExFXG4gIGFyci53cml0ZUZsb2F0QkUgPSBCUC53cml0ZUZsb2F0QkVcbiAgYXJyLndyaXRlRG91YmxlTEUgPSBCUC53cml0ZURvdWJsZUxFXG4gIGFyci53cml0ZURvdWJsZUJFID0gQlAud3JpdGVEb3VibGVCRVxuICBhcnIuZmlsbCA9IEJQLmZpbGxcbiAgYXJyLmluc3BlY3QgPSBCUC5pbnNwZWN0XG4gIGFyci50b0FycmF5QnVmZmVyID0gQlAudG9BcnJheUJ1ZmZlclxuXG4gIHJldHVybiBhcnJcbn1cblxudmFyIElOVkFMSURfQkFTRTY0X1JFID0gL1teK1xcLzAtOUEtWmEtei1fXS9nXG5cbmZ1bmN0aW9uIGJhc2U2NGNsZWFuIChzdHIpIHtcbiAgLy8gTm9kZSBzdHJpcHMgb3V0IGludmFsaWQgY2hhcmFjdGVycyBsaWtlIFxcbiBhbmQgXFx0IGZyb20gdGhlIHN0cmluZywgYmFzZTY0LWpzIGRvZXMgbm90XG4gIHN0ciA9IHN0cmluZ3RyaW0oc3RyKS5yZXBsYWNlKElOVkFMSURfQkFTRTY0X1JFLCAnJylcbiAgLy8gTm9kZSBjb252ZXJ0cyBzdHJpbmdzIHdpdGggbGVuZ3RoIDwgMiB0byAnJ1xuICBpZiAoc3RyLmxlbmd0aCA8IDIpIHJldHVybiAnJ1xuICAvLyBOb2RlIGFsbG93cyBmb3Igbm9uLXBhZGRlZCBiYXNlNjQgc3RyaW5ncyAobWlzc2luZyB0cmFpbGluZyA9PT0pLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgd2hpbGUgKHN0ci5sZW5ndGggJSA0ICE9PSAwKSB7XG4gICAgc3RyID0gc3RyICsgJz0nXG4gIH1cbiAgcmV0dXJuIHN0clxufVxuXG5mdW5jdGlvbiBzdHJpbmd0cmltIChzdHIpIHtcbiAgaWYgKHN0ci50cmltKSByZXR1cm4gc3RyLnRyaW0oKVxuICByZXR1cm4gc3RyLnJlcGxhY2UoL15cXHMrfFxccyskL2csICcnKVxufVxuXG5mdW5jdGlvbiB0b0hleCAobikge1xuICBpZiAobiA8IDE2KSByZXR1cm4gJzAnICsgbi50b1N0cmluZygxNilcbiAgcmV0dXJuIG4udG9TdHJpbmcoMTYpXG59XG5cbmZ1bmN0aW9uIHV0ZjhUb0J5dGVzIChzdHJpbmcsIHVuaXRzKSB7XG4gIHVuaXRzID0gdW5pdHMgfHwgSW5maW5pdHlcbiAgdmFyIGNvZGVQb2ludFxuICB2YXIgbGVuZ3RoID0gc3RyaW5nLmxlbmd0aFxuICB2YXIgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcbiAgdmFyIGJ5dGVzID0gW11cblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgY29kZVBvaW50ID0gc3RyaW5nLmNoYXJDb2RlQXQoaSlcblxuICAgIC8vIGlzIHN1cnJvZ2F0ZSBjb21wb25lbnRcbiAgICBpZiAoY29kZVBvaW50ID4gMHhEN0ZGICYmIGNvZGVQb2ludCA8IDB4RTAwMCkge1xuICAgICAgLy8gbGFzdCBjaGFyIHdhcyBhIGxlYWRcbiAgICAgIGlmICghbGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgICAvLyBubyBsZWFkIHlldFxuICAgICAgICBpZiAoY29kZVBvaW50ID4gMHhEQkZGKSB7XG4gICAgICAgICAgLy8gdW5leHBlY3RlZCB0cmFpbFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH0gZWxzZSBpZiAoaSArIDEgPT09IGxlbmd0aCkge1xuICAgICAgICAgIC8vIHVucGFpcmVkIGxlYWRcbiAgICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gdmFsaWQgbGVhZFxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG5cbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gMiBsZWFkcyBpbiBhIHJvd1xuICAgICAgaWYgKGNvZGVQb2ludCA8IDB4REMwMCkge1xuICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgbGVhZFN1cnJvZ2F0ZSA9IGNvZGVQb2ludFxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyB2YWxpZCBzdXJyb2dhdGUgcGFpclxuICAgICAgY29kZVBvaW50ID0gKGxlYWRTdXJyb2dhdGUgLSAweEQ4MDAgPDwgMTAgfCBjb2RlUG9pbnQgLSAweERDMDApICsgMHgxMDAwMFxuICAgIH0gZWxzZSBpZiAobGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgLy8gdmFsaWQgYm1wIGNoYXIsIGJ1dCBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgfVxuXG4gICAgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcblxuICAgIC8vIGVuY29kZSB1dGY4XG4gICAgaWYgKGNvZGVQb2ludCA8IDB4ODApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMSkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChjb2RlUG9pbnQpXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDgwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAyKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2IHwgMHhDMCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMykgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyB8IDB4RTAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDQpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDEyIHwgMHhGMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2ICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjb2RlIHBvaW50JylcbiAgICB9XG4gIH1cblxuICByZXR1cm4gYnl0ZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlUb0J5dGVzIChzdHIpIHtcbiAgdmFyIGJ5dGVBcnJheSA9IFtdXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgLy8gTm9kZSdzIGNvZGUgc2VlbXMgdG8gYmUgZG9pbmcgdGhpcyBhbmQgbm90ICYgMHg3Ri4uXG4gICAgYnl0ZUFycmF5LnB1c2goc3RyLmNoYXJDb2RlQXQoaSkgJiAweEZGKVxuICB9XG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gdXRmMTZsZVRvQnl0ZXMgKHN0ciwgdW5pdHMpIHtcbiAgdmFyIGMsIGhpLCBsb1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcblxuICAgIGMgPSBzdHIuY2hhckNvZGVBdChpKVxuICAgIGhpID0gYyA+PiA4XG4gICAgbG8gPSBjICUgMjU2XG4gICAgYnl0ZUFycmF5LnB1c2gobG8pXG4gICAgYnl0ZUFycmF5LnB1c2goaGkpXG4gIH1cblxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIGJhc2U2NFRvQnl0ZXMgKHN0cikge1xuICByZXR1cm4gYmFzZTY0LnRvQnl0ZUFycmF5KGJhc2U2NGNsZWFuKHN0cikpXG59XG5cbmZ1bmN0aW9uIGJsaXRCdWZmZXIgKHNyYywgZHN0LCBvZmZzZXQsIGxlbmd0aCkge1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKChpICsgb2Zmc2V0ID49IGRzdC5sZW5ndGgpIHx8IChpID49IHNyYy5sZW5ndGgpKSBicmVha1xuICAgIGRzdFtpICsgb2Zmc2V0XSA9IHNyY1tpXVxuICB9XG4gIHJldHVybiBpXG59XG4iLCJ2YXIgbG9va3VwID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky8nO1xuXG47KGZ1bmN0aW9uIChleHBvcnRzKSB7XG5cdCd1c2Ugc3RyaWN0JztcblxuICB2YXIgQXJyID0gKHR5cGVvZiBVaW50OEFycmF5ICE9PSAndW5kZWZpbmVkJylcbiAgICA/IFVpbnQ4QXJyYXlcbiAgICA6IEFycmF5XG5cblx0dmFyIFBMVVMgICA9ICcrJy5jaGFyQ29kZUF0KDApXG5cdHZhciBTTEFTSCAgPSAnLycuY2hhckNvZGVBdCgwKVxuXHR2YXIgTlVNQkVSID0gJzAnLmNoYXJDb2RlQXQoMClcblx0dmFyIExPV0VSICA9ICdhJy5jaGFyQ29kZUF0KDApXG5cdHZhciBVUFBFUiAgPSAnQScuY2hhckNvZGVBdCgwKVxuXHR2YXIgUExVU19VUkxfU0FGRSA9ICctJy5jaGFyQ29kZUF0KDApXG5cdHZhciBTTEFTSF9VUkxfU0FGRSA9ICdfJy5jaGFyQ29kZUF0KDApXG5cblx0ZnVuY3Rpb24gZGVjb2RlIChlbHQpIHtcblx0XHR2YXIgY29kZSA9IGVsdC5jaGFyQ29kZUF0KDApXG5cdFx0aWYgKGNvZGUgPT09IFBMVVMgfHxcblx0XHQgICAgY29kZSA9PT0gUExVU19VUkxfU0FGRSlcblx0XHRcdHJldHVybiA2MiAvLyAnKydcblx0XHRpZiAoY29kZSA9PT0gU0xBU0ggfHxcblx0XHQgICAgY29kZSA9PT0gU0xBU0hfVVJMX1NBRkUpXG5cdFx0XHRyZXR1cm4gNjMgLy8gJy8nXG5cdFx0aWYgKGNvZGUgPCBOVU1CRVIpXG5cdFx0XHRyZXR1cm4gLTEgLy9ubyBtYXRjaFxuXHRcdGlmIChjb2RlIDwgTlVNQkVSICsgMTApXG5cdFx0XHRyZXR1cm4gY29kZSAtIE5VTUJFUiArIDI2ICsgMjZcblx0XHRpZiAoY29kZSA8IFVQUEVSICsgMjYpXG5cdFx0XHRyZXR1cm4gY29kZSAtIFVQUEVSXG5cdFx0aWYgKGNvZGUgPCBMT1dFUiArIDI2KVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBMT1dFUiArIDI2XG5cdH1cblxuXHRmdW5jdGlvbiBiNjRUb0J5dGVBcnJheSAoYjY0KSB7XG5cdFx0dmFyIGksIGosIGwsIHRtcCwgcGxhY2VIb2xkZXJzLCBhcnJcblxuXHRcdGlmIChiNjQubGVuZ3RoICUgNCA+IDApIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzdHJpbmcuIExlbmd0aCBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgNCcpXG5cdFx0fVxuXG5cdFx0Ly8gdGhlIG51bWJlciBvZiBlcXVhbCBzaWducyAocGxhY2UgaG9sZGVycylcblx0XHQvLyBpZiB0aGVyZSBhcmUgdHdvIHBsYWNlaG9sZGVycywgdGhhbiB0aGUgdHdvIGNoYXJhY3RlcnMgYmVmb3JlIGl0XG5cdFx0Ly8gcmVwcmVzZW50IG9uZSBieXRlXG5cdFx0Ly8gaWYgdGhlcmUgaXMgb25seSBvbmUsIHRoZW4gdGhlIHRocmVlIGNoYXJhY3RlcnMgYmVmb3JlIGl0IHJlcHJlc2VudCAyIGJ5dGVzXG5cdFx0Ly8gdGhpcyBpcyBqdXN0IGEgY2hlYXAgaGFjayB0byBub3QgZG8gaW5kZXhPZiB0d2ljZVxuXHRcdHZhciBsZW4gPSBiNjQubGVuZ3RoXG5cdFx0cGxhY2VIb2xkZXJzID0gJz0nID09PSBiNjQuY2hhckF0KGxlbiAtIDIpID8gMiA6ICc9JyA9PT0gYjY0LmNoYXJBdChsZW4gLSAxKSA/IDEgOiAwXG5cblx0XHQvLyBiYXNlNjQgaXMgNC8zICsgdXAgdG8gdHdvIGNoYXJhY3RlcnMgb2YgdGhlIG9yaWdpbmFsIGRhdGFcblx0XHRhcnIgPSBuZXcgQXJyKGI2NC5sZW5ndGggKiAzIC8gNCAtIHBsYWNlSG9sZGVycylcblxuXHRcdC8vIGlmIHRoZXJlIGFyZSBwbGFjZWhvbGRlcnMsIG9ubHkgZ2V0IHVwIHRvIHRoZSBsYXN0IGNvbXBsZXRlIDQgY2hhcnNcblx0XHRsID0gcGxhY2VIb2xkZXJzID4gMCA/IGI2NC5sZW5ndGggLSA0IDogYjY0Lmxlbmd0aFxuXG5cdFx0dmFyIEwgPSAwXG5cblx0XHRmdW5jdGlvbiBwdXNoICh2KSB7XG5cdFx0XHRhcnJbTCsrXSA9IHZcblx0XHR9XG5cblx0XHRmb3IgKGkgPSAwLCBqID0gMDsgaSA8IGw7IGkgKz0gNCwgaiArPSAzKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDE4KSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDEyKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMikpIDw8IDYpIHwgZGVjb2RlKGI2NC5jaGFyQXQoaSArIDMpKVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwMDApID4+IDE2KVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwKSA+PiA4KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH1cblxuXHRcdGlmIChwbGFjZUhvbGRlcnMgPT09IDIpIHtcblx0XHRcdHRtcCA9IChkZWNvZGUoYjY0LmNoYXJBdChpKSkgPDwgMikgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA+PiA0KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH0gZWxzZSBpZiAocGxhY2VIb2xkZXJzID09PSAxKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDEwKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDQpIHwgKGRlY29kZShiNjQuY2hhckF0KGkgKyAyKSkgPj4gMilcblx0XHRcdHB1c2goKHRtcCA+PiA4KSAmIDB4RkYpXG5cdFx0XHRwdXNoKHRtcCAmIDB4RkYpXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGFyclxuXHR9XG5cblx0ZnVuY3Rpb24gdWludDhUb0Jhc2U2NCAodWludDgpIHtcblx0XHR2YXIgaSxcblx0XHRcdGV4dHJhQnl0ZXMgPSB1aW50OC5sZW5ndGggJSAzLCAvLyBpZiB3ZSBoYXZlIDEgYnl0ZSBsZWZ0LCBwYWQgMiBieXRlc1xuXHRcdFx0b3V0cHV0ID0gXCJcIixcblx0XHRcdHRlbXAsIGxlbmd0aFxuXG5cdFx0ZnVuY3Rpb24gZW5jb2RlIChudW0pIHtcblx0XHRcdHJldHVybiBsb29rdXAuY2hhckF0KG51bSlcblx0XHR9XG5cblx0XHRmdW5jdGlvbiB0cmlwbGV0VG9CYXNlNjQgKG51bSkge1xuXHRcdFx0cmV0dXJuIGVuY29kZShudW0gPj4gMTggJiAweDNGKSArIGVuY29kZShudW0gPj4gMTIgJiAweDNGKSArIGVuY29kZShudW0gPj4gNiAmIDB4M0YpICsgZW5jb2RlKG51bSAmIDB4M0YpXG5cdFx0fVxuXG5cdFx0Ly8gZ28gdGhyb3VnaCB0aGUgYXJyYXkgZXZlcnkgdGhyZWUgYnl0ZXMsIHdlJ2xsIGRlYWwgd2l0aCB0cmFpbGluZyBzdHVmZiBsYXRlclxuXHRcdGZvciAoaSA9IDAsIGxlbmd0aCA9IHVpbnQ4Lmxlbmd0aCAtIGV4dHJhQnl0ZXM7IGkgPCBsZW5ndGg7IGkgKz0gMykge1xuXHRcdFx0dGVtcCA9ICh1aW50OFtpXSA8PCAxNikgKyAodWludDhbaSArIDFdIDw8IDgpICsgKHVpbnQ4W2kgKyAyXSlcblx0XHRcdG91dHB1dCArPSB0cmlwbGV0VG9CYXNlNjQodGVtcClcblx0XHR9XG5cblx0XHQvLyBwYWQgdGhlIGVuZCB3aXRoIHplcm9zLCBidXQgbWFrZSBzdXJlIHRvIG5vdCBmb3JnZXQgdGhlIGV4dHJhIGJ5dGVzXG5cdFx0c3dpdGNoIChleHRyYUJ5dGVzKSB7XG5cdFx0XHRjYXNlIDE6XG5cdFx0XHRcdHRlbXAgPSB1aW50OFt1aW50OC5sZW5ndGggLSAxXVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKHRlbXAgPj4gMilcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA8PCA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSAnPT0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0XHRjYXNlIDI6XG5cdFx0XHRcdHRlbXAgPSAodWludDhbdWludDgubGVuZ3RoIC0gMl0gPDwgOCkgKyAodWludDhbdWludDgubGVuZ3RoIC0gMV0pXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUodGVtcCA+PiAxMClcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA+PiA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPDwgMikgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gJz0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG91dHB1dFxuXHR9XG5cblx0ZXhwb3J0cy50b0J5dGVBcnJheSA9IGI2NFRvQnl0ZUFycmF5XG5cdGV4cG9ydHMuZnJvbUJ5dGVBcnJheSA9IHVpbnQ4VG9CYXNlNjRcbn0odHlwZW9mIGV4cG9ydHMgPT09ICd1bmRlZmluZWQnID8gKHRoaXMuYmFzZTY0anMgPSB7fSkgOiBleHBvcnRzKSlcbiIsImV4cG9ydHMucmVhZCA9IGZ1bmN0aW9uIChidWZmZXIsIG9mZnNldCwgaXNMRSwgbUxlbiwgbkJ5dGVzKSB7XG4gIHZhciBlLCBtXG4gIHZhciBlTGVuID0gbkJ5dGVzICogOCAtIG1MZW4gLSAxXG4gIHZhciBlTWF4ID0gKDEgPDwgZUxlbikgLSAxXG4gIHZhciBlQmlhcyA9IGVNYXggPj4gMVxuICB2YXIgbkJpdHMgPSAtN1xuICB2YXIgaSA9IGlzTEUgPyAobkJ5dGVzIC0gMSkgOiAwXG4gIHZhciBkID0gaXNMRSA/IC0xIDogMVxuICB2YXIgcyA9IGJ1ZmZlcltvZmZzZXQgKyBpXVxuXG4gIGkgKz0gZFxuXG4gIGUgPSBzICYgKCgxIDw8ICgtbkJpdHMpKSAtIDEpXG4gIHMgPj49ICgtbkJpdHMpXG4gIG5CaXRzICs9IGVMZW5cbiAgZm9yICg7IG5CaXRzID4gMDsgZSA9IGUgKiAyNTYgKyBidWZmZXJbb2Zmc2V0ICsgaV0sIGkgKz0gZCwgbkJpdHMgLT0gOCkge31cblxuICBtID0gZSAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBlID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBtTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IG0gPSBtICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgaWYgKGUgPT09IDApIHtcbiAgICBlID0gMSAtIGVCaWFzXG4gIH0gZWxzZSBpZiAoZSA9PT0gZU1heCkge1xuICAgIHJldHVybiBtID8gTmFOIDogKChzID8gLTEgOiAxKSAqIEluZmluaXR5KVxuICB9IGVsc2Uge1xuICAgIG0gPSBtICsgTWF0aC5wb3coMiwgbUxlbilcbiAgICBlID0gZSAtIGVCaWFzXG4gIH1cbiAgcmV0dXJuIChzID8gLTEgOiAxKSAqIG0gKiBNYXRoLnBvdygyLCBlIC0gbUxlbilcbn1cblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uIChidWZmZXIsIHZhbHVlLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbSwgY1xuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIHJ0ID0gKG1MZW4gPT09IDIzID8gTWF0aC5wb3coMiwgLTI0KSAtIE1hdGgucG93KDIsIC03NykgOiAwKVxuICB2YXIgaSA9IGlzTEUgPyAwIDogKG5CeXRlcyAtIDEpXG4gIHZhciBkID0gaXNMRSA/IDEgOiAtMVxuICB2YXIgcyA9IHZhbHVlIDwgMCB8fCAodmFsdWUgPT09IDAgJiYgMSAvIHZhbHVlIDwgMCkgPyAxIDogMFxuXG4gIHZhbHVlID0gTWF0aC5hYnModmFsdWUpXG5cbiAgaWYgKGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICBtID0gaXNOYU4odmFsdWUpID8gMSA6IDBcbiAgICBlID0gZU1heFxuICB9IGVsc2Uge1xuICAgIGUgPSBNYXRoLmZsb29yKE1hdGgubG9nKHZhbHVlKSAvIE1hdGguTE4yKVxuICAgIGlmICh2YWx1ZSAqIChjID0gTWF0aC5wb3coMiwgLWUpKSA8IDEpIHtcbiAgICAgIGUtLVxuICAgICAgYyAqPSAyXG4gICAgfVxuICAgIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgdmFsdWUgKz0gcnQgLyBjXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbHVlICs9IHJ0ICogTWF0aC5wb3coMiwgMSAtIGVCaWFzKVxuICAgIH1cbiAgICBpZiAodmFsdWUgKiBjID49IDIpIHtcbiAgICAgIGUrK1xuICAgICAgYyAvPSAyXG4gICAgfVxuXG4gICAgaWYgKGUgKyBlQmlhcyA+PSBlTWF4KSB7XG4gICAgICBtID0gMFxuICAgICAgZSA9IGVNYXhcbiAgICB9IGVsc2UgaWYgKGUgKyBlQmlhcyA+PSAxKSB7XG4gICAgICBtID0gKHZhbHVlICogYyAtIDEpICogTWF0aC5wb3coMiwgbUxlbilcbiAgICAgIGUgPSBlICsgZUJpYXNcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IHZhbHVlICogTWF0aC5wb3coMiwgZUJpYXMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gMFxuICAgIH1cbiAgfVxuXG4gIGZvciAoOyBtTGVuID49IDg7IGJ1ZmZlcltvZmZzZXQgKyBpXSA9IG0gJiAweGZmLCBpICs9IGQsIG0gLz0gMjU2LCBtTGVuIC09IDgpIHt9XG5cbiAgZSA9IChlIDw8IG1MZW4pIHwgbVxuICBlTGVuICs9IG1MZW5cbiAgZm9yICg7IGVMZW4gPiAwOyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBlICYgMHhmZiwgaSArPSBkLCBlIC89IDI1NiwgZUxlbiAtPSA4KSB7fVxuXG4gIGJ1ZmZlcltvZmZzZXQgKyBpIC0gZF0gfD0gcyAqIDEyOFxufVxuIiwiXG4vKipcbiAqIGlzQXJyYXlcbiAqL1xuXG52YXIgaXNBcnJheSA9IEFycmF5LmlzQXJyYXk7XG5cbi8qKlxuICogdG9TdHJpbmdcbiAqL1xuXG52YXIgc3RyID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztcblxuLyoqXG4gKiBXaGV0aGVyIG9yIG5vdCB0aGUgZ2l2ZW4gYHZhbGBcbiAqIGlzIGFuIGFycmF5LlxuICpcbiAqIGV4YW1wbGU6XG4gKlxuICogICAgICAgIGlzQXJyYXkoW10pO1xuICogICAgICAgIC8vID4gdHJ1ZVxuICogICAgICAgIGlzQXJyYXkoYXJndW1lbnRzKTtcbiAqICAgICAgICAvLyA+IGZhbHNlXG4gKiAgICAgICAgaXNBcnJheSgnJyk7XG4gKiAgICAgICAgLy8gPiBmYWxzZVxuICpcbiAqIEBwYXJhbSB7bWl4ZWR9IHZhbFxuICogQHJldHVybiB7Ym9vbH1cbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGlzQXJyYXkgfHwgZnVuY3Rpb24gKHZhbCkge1xuICByZXR1cm4gISEgdmFsICYmICdbb2JqZWN0IEFycmF5XScgPT0gc3RyLmNhbGwodmFsKTtcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJ2ZXJzaW9uXCI6IFwiXCJcbn1cbiIsIi8qKlxuICogRXBpY2VudGVyIEphdmFzY3JpcHQgbGlicmFyaWVzXG4gKiB2PCU9IHZlcnNpb24gJT5cbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9mb3Jpby9lcGljZW50ZXItanMtbGlic1xuICovXG5cbnZhciBGID0ge1xuICAgIHV0aWw6IHt9LFxuICAgIGZhY3Rvcnk6IHt9LFxuICAgIHRyYW5zcG9ydDoge30sXG4gICAgc3RvcmU6IHt9LFxuICAgIHNlcnZpY2U6IHt9LFxuICAgIG1hbmFnZXI6IHtcbiAgICAgICAgc3RyYXRlZ3k6IHt9XG4gICAgfSxcblxufTtcblxuRi51dGlsLnF1ZXJ5ID0gcmVxdWlyZSgnLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbkYudXRpbC5tYWtlU2VxdWVuY2UgPSByZXF1aXJlKCcuL3V0aWwvbWFrZS1zZXF1ZW5jZScpO1xuRi51dGlsLnJ1biA9IHJlcXVpcmUoJy4vdXRpbC9ydW4tdXRpbCcpO1xuRi51dGlsLmNsYXNzRnJvbSA9IHJlcXVpcmUoJy4vdXRpbC9pbmhlcml0Jyk7XG5cbkYuZmFjdG9yeS5UcmFuc3BvcnQgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5GLnRyYW5zcG9ydC5BamF4ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvYWpheC1odHRwLXRyYW5zcG9ydCcpO1xuXG5GLnNlcnZpY2UuVVJMID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xuRi5zZXJ2aWNlLkNvbmZpZyA9IHJlcXVpcmUoJy4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbkYuc2VydmljZS5SdW4gPSByZXF1aXJlKCcuL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRmlsZSA9IHJlcXVpcmUoJy4vc2VydmljZS9hZG1pbi1maWxlLXNlcnZpY2UnKTtcbkYuc2VydmljZS5WYXJpYWJsZXMgPSByZXF1aXJlKCcuL3NlcnZpY2UvdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRGF0YSA9IHJlcXVpcmUoJy4vc2VydmljZS9kYXRhLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuQXV0aCA9IHJlcXVpcmUoJy4vc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuV29ybGQgPSByZXF1aXJlKCcuL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5TdGF0ZSA9IHJlcXVpcmUoJy4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLlVzZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLk1lbWJlciA9IHJlcXVpcmUoJy4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Bc3NldCA9IHJlcXVpcmUoJy4vc2VydmljZS9hc3NldC1hcGktYWRhcHRlcicpO1xuXG5GLnN0b3JlLkNvb2tpZSA9IHJlcXVpcmUoJy4vc3RvcmUvY29va2llLXN0b3JlJyk7XG5GLmZhY3RvcnkuU3RvcmUgPSByZXF1aXJlKCcuL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcblxuRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvc2NlbmFyaW8tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLlJ1bk1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2F1dGgtbWFuYWdlcicpO1xuRi5tYW5hZ2VyLldvcmxkTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvd29ybGQtbWFuYWdlcicpO1xuXG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ2Fsd2F5cy1uZXcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvYWx3YXlzLW5ldy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5Wydjb25kaXRpb25hbC1jcmVhdGlvbiddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5LmlkZW50aXR5ID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9pZGVudGl0eS1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtcGVyc2lzdGVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLWluaXRpYWxpemVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpO1xuXG5GLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXInKTtcbkYuc2VydmljZS5DaGFubmVsID0gcmVxdWlyZSgnLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xuXG5GLnZlcnNpb24gPSAnPCU9IHZlcnNpb24gJT4nO1xuRi5hcGkgPSByZXF1aXJlKCcuL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuZ2xvYmFsLkYgPSBGO1xubW9kdWxlLmV4cG9ydHMgPSBGO1xuIiwiLyoqXG4qICMjIEF1dGhvcml6YXRpb24gTWFuYWdlclxuKlxuKiBUaGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIG1hbmFnZSB1c2VyIGF1dGhlbnRpY2F0aW9uIChsb2dnaW5nIGluIGFuZCBvdXQpIGFuZCBhdXRob3JpemF0aW9uIChrZWVwaW5nIHRyYWNrIG9mIHRva2Vucywgc2Vzc2lvbnMsIGFuZCBncm91cHMpIGZvciBwcm9qZWN0cy5cbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBpcyBtb3N0IHVzZWZ1bCBmb3IgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSB3aXRoIGFuIGFjY2VzcyBsZXZlbCBvZiBbQXV0aGVudGljYXRlZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2FjY2VzcykuIFRoZXNlIHByb2plY3RzIGFyZSBhY2Nlc3NlZCBieSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiBvbmUgb3IgbW9yZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS5cbipcbiogIyMjI1VzaW5nIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXJcbipcbiogVG8gdXNlIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZDpcbipcbiogICAgICAgdmFyIGF1dGhNZ3IgPSBuZXcgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKHtcbiogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgIHVzZXJOYW1lOiAnZW5kdXNlcjEnLFxuKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiogICAgICAgfSk7XG4qICAgICAgIGF1dGhNZ3IubG9naW4oKS50aGVuKGZ1bmN0aW9uICgpIHtcbiogICAgICAgICAgIGF1dGhNZ3IuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuKiAgICAgICB9KTtcbipcbipcbiogVGhlIGBvcHRpb25zYCBvYmplY3QgcGFzc2VkIHRvIHRoZSBgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKClgIGNhbGwgY2FuIGluY2x1ZGU6XG4qXG4qICAgKiBgYWNjb3VudGA6IFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICogYHVzZXJOYW1lYDogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLlxuKiAgICogYHBhc3N3b3JkYDogUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLlxuKiAgICogYHByb2plY3RgOiBUaGUgKipQcm9qZWN0IElEKiogZm9yIHRoZSBwcm9qZWN0IHRvIGxvZyB0aGlzIHVzZXIgaW50by4gT3B0aW9uYWwuXG4qICAgKiBgZ3JvdXBJZGA6IElkIG9mIHRoZSBncm91cCB0byB3aGljaCBgdXNlck5hbWVgIGJlbG9uZ3MuIFJlcXVpcmVkIGZvciBlbmQgdXNlcnMgaWYgdGhlIGBwcm9qZWN0YCBpcyBzcGVjaWZpZWQuXG4qXG4qIElmIHlvdSBwcmVmZXIgc3RhcnRpbmcgZnJvbSBhIHRlbXBsYXRlLCB0aGUgRXBpY2VudGVyIEpTIExpYnMgW0xvZ2luIENvbXBvbmVudF0oLi4vLi4vI2NvbXBvbmVudHMpIHVzZXMgdGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBhcyB3ZWxsLiBUaGlzIHNhbXBsZSBIVE1MIHBhZ2UgKGFuZCBhc3NvY2lhdGVkIENTUyBhbmQgSlMgZmlsZXMpIHByb3ZpZGVzIGEgbG9naW4gZm9ybSBmb3IgdGVhbSBtZW1iZXJzIGFuZCBlbmQgdXNlcnMgb2YgeW91ciBwcm9qZWN0LiBJdCBhbHNvIGluY2x1ZGVzIGEgZ3JvdXAgc2VsZWN0b3IgZm9yIGVuZCB1c2VycyB0aGF0IGFyZSBtZW1iZXJzIG9mIG11bHRpcGxlIGdyb3Vwcy5cbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBBdXRoQWRhcHRlciA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xudmFyIE1lbWJlckFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlcicpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIEJ1ZmZlciA9IHJlcXVpcmUoJ2J1ZmZlcicpLkJ1ZmZlcjtcbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4va2V5LW5hbWVzJyk7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBXaGVyZSB0byBzdG9yZSB1c2VyIGFjY2VzcyB0b2tlbnMgZm9yIHRlbXBvcmFyeSBhY2Nlc3MuIERlZmF1bHRzIHRvIHN0b3JpbmcgaW4gYSBjb29raWUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBzdG9yZTogeyBzeW5jaHJvbm91czogdHJ1ZSB9XG59O1xuXG52YXIgRVBJX0NPT0tJRV9LRVkgPSBrZXlOYW1lcy5FUElfQ09PS0lFX0tFWTtcbnZhciBFUElfU0VTU0lPTl9LRVkgPSBrZXlOYW1lcy5FUElfU0VTU0lPTl9LRVk7XG52YXIgc3RvcmU7XG52YXIgdG9rZW47XG52YXIgc2Vzc2lvbjtcblxuZnVuY3Rpb24gc2F2ZVNlc3Npb24odXNlckluZm8sIHN0b3JlKSB7XG4gICAgdmFyIHNlcmlhbGl6ZWQgPSBKU09OLnN0cmluZ2lmeSh1c2VySW5mbyk7XG4gICAgc3RvcmUuc2V0KEVQSV9TRVNTSU9OX0tFWSwgc2VyaWFsaXplZCk7XG5cbiAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgLy9qc2NzOmRpc2FibGVcbiAgICBzdG9yZS5zZXQoRVBJX0NPT0tJRV9LRVksIHVzZXJJbmZvLmF1dGhfdG9rZW4pO1xufVxuXG5mdW5jdGlvbiBnZXRTZXNzaW9uKHN0b3JlKSB7XG4gICAgdmFyIHNlc3Npb24gPSBzdG9yZS5nZXQoRVBJX1NFU1NJT05fS0VZKSB8fCAne30nO1xuICAgIHJldHVybiBKU09OLnBhcnNlKHNlc3Npb24pO1xufVxuXG5mdW5jdGlvbiBBdXRoTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZSh0aGlzLm9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB0aGlzLm9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICAvLyBudWxsIG1pZ2h0IHNwZWNpZmllZCB0byBkaXNhYmxlIHByb2plY3QgZmlsdGVyaW5nXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wcm9qZWN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdGhpcy5zdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh0aGlzLm9wdGlvbnMuc3RvcmUpO1xuICAgIHNlc3Npb24gPSBnZXRTZXNzaW9uKHRoaXMuc3RvcmUpO1xuICAgIHRva2VuID0gdGhpcy5zdG9yZS5nZXQoRVBJX0NPT0tJRV9LRVkpIHx8ICcnO1xuICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAvL2pzY3M6ZGlzYWJsZVxuICAgIHRoaXMuYXV0aEFkYXB0ZXIgPSBuZXcgQXV0aEFkYXB0ZXIodGhpcy5vcHRpb25zLCB7IHRva2VuOiBzZXNzaW9uLmF1dGhfdG9rZW4gfSk7XG59XG5cbnZhciBfZmluZFVzZXJJbkdyb3VwID0gZnVuY3Rpb24gKG1lbWJlcnMsIGlkKSB7XG4gICAgZm9yICh2YXIgaiA9IDA7IGo8bWVtYmVycy5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAobWVtYmVyc1tqXS51c2VySWQgPT09IGlkKSB7XG4gICAgICAgICAgICByZXR1cm4gbWVtYmVyc1tqXTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgcmV0dXJuIG51bGw7XG59O1xuXG5BdXRoTWFuYWdlci5wcm90b3R5cGUgPSAkLmV4dGVuZChBdXRoTWFuYWdlci5wcm90b3R5cGUsIHtcblxuICAgIC8qKlxuICAgICogTG9ncyB1c2VyIGluLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dpbih7XG4gICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgKiAgICAgICAgICAgdXNlck5hbWU6ICdlbmR1c2VyMScsXG4gICAgKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiAgICAqICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gZXhhY3RseSBvbmUgZ3JvdXBcbiAgICAqICAgICAgICAgICAgICAgLy8gKG9yIGlmIHRoZSBsb2dpbigpIGNhbGwgaXMgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGUgZ3JvdXAgaWQpXG4gICAgKiAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIGhlcmVcbiAgICAqICAgICAgICAgICB9KVxuICAgICogICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIG11bHRpcGxlIGdyb3VwcyxcbiAgICAqICAgICAgICAgICAgICAgLy8gdGhlIGxvZ2luKCkgY2FsbCBmYWlsc1xuICAgICogICAgICAgICAgICAgICAvLyBhbmQgcmV0dXJucyBhbGwgZ3JvdXBzIG9mIHdoaWNoIHRoZSB1c2VyIGlzIGEgbWVtYmVyXG4gICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IHN0YXR1c09iai51c2VyR3JvdXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5uYW1lLCBzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5ncm91cElkKTtcbiAgICAqICAgICAgICAgICAgICAgfVxuICAgICogICAgICAgICAgIH0pO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLiBJZiBub3QgcGFzc2VkIGluIHdoZW4gY3JlYXRpbmcgYW4gaW5zdGFuY2Ugb2YgdGhlIG1hbmFnZXIgKGBGLm1hbmFnZXIuQXV0aE1hbmFnZXIoKWApLCB0aGVzZSBvcHRpb25zIHNob3VsZCBpbmNsdWRlOlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmFjY291bnRgIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnVzZXJOYW1lYCBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMucGFzc3dvcmRgIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5wcm9qZWN0YCAoT3B0aW9uYWwpIFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhlIHByb2plY3QgdG8gbG9nIHRoaXMgdXNlciBpbnRvLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpZiB0aGUgYHByb2plY3RgIGlzIHNwZWNpZmllZCBhbmQgaWYgdGhlIGVuZCB1c2VycyBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3RoZXJ3aXNlIG9wdGlvbmFsLlxuICAgICovXG4gICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AsIGVycm9yOiAkLm5vb3AgfSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuICAgICAgICB2YXIgb3V0RXJyb3IgPSBhZGFwdGVyT3B0aW9ucy5lcnJvcjtcbiAgICAgICAgdmFyIGdyb3VwSWQgPSBhZGFwdGVyT3B0aW9ucy5ncm91cElkO1xuXG4gICAgICAgIHZhciBhY2NvdW50TmFtZSA9IChvcHRpb25zICYmIG9wdGlvbnMuYWNjb3VudCkgPyBvcHRpb25zLmFjY291bnQgOiB0aGlzLm9wdGlvbnMuYWNjb3VudDtcbiAgICAgICAgdmFyIHByb2plY3ROYW1lID0gKG9wdGlvbnMgJiYgb3B0aW9ucy5wcm9qZWN0KSA/IG9wdGlvbnMucHJvamVjdCA6IHRoaXMub3B0aW9ucy5wcm9qZWN0O1xuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuc3RvcmUucm9vdCA9PT0gdW5kZWZpbmVkICYmIGFjY291bnROYW1lICYmIHByb2plY3ROYW1lKSB7XG4gICAgICAgICAgICB0aGlzLnN0b3JlLnNlcnZpY2VPcHRpb25zLnJvb3QgPSAnL2FwcC8nICsgYWNjb3VudE5hbWUgKyAnLycgKyBwcm9qZWN0TmFtZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBkZWNvZGVUb2tlbiA9IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgICAgdmFyIGVuY29kZWQgPSB0b2tlbi5zcGxpdCgnLicpWzFdO1xuICAgICAgICAgICAgd2hpbGUgKGVuY29kZWQubGVuZ3RoICUgNCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIGVuY29kZWQgKz0gJz0nO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZGVjb2RlID0gd2luZG93LmF0b2IgPyB3aW5kb3cuYXRvYiA6IGZ1bmN0aW9uIChlbmNvZGVkKSB7IHJldHVybiBuZXcgQnVmZmVyKGVuY29kZWQsICdiYXNlNjQnKS50b1N0cmluZygnYXNjaWknKTsgfTtcblxuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGVjb2RlKGVuY29kZWQpKTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgaGFuZGxlR3JvdXBFcnJvciA9IGZ1bmN0aW9uIChtZXNzYWdlLCBzdGF0dXNDb2RlLCBkYXRhKSB7XG4gICAgICAgICAgICAvLyBsb2dvdXQgdGhlIHVzZXIgc2luY2UgaXQncyBpbiBhbiBpbnZhbGlkIHN0YXRlIHdpdGggbm8gZ3JvdXAgc2VsZWN0ZWRcbiAgICAgICAgICAgIF90aGlzLmxvZ291dCgpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBlcnJvciA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkYXRhLCB7IHN0YXR1c1RleHQ6IG1lc3NhZ2UsIHN0YXR1czogc3RhdHVzQ29kZSB9KTtcbiAgICAgICAgICAgICAgICAkZC5yZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZVN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAgICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgICAgICB0b2tlbiA9IHJlc3BvbnNlLmFjY2Vzc190b2tlbjtcbiAgICAgICAgICAgIHZhciB1c2VySW5mbyA9IGRlY29kZVRva2VuKHRva2VuKTtcbiAgICAgICAgICAgIHZhciB1c2VyR3JvdXBPcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIGFkYXB0ZXJPcHRpb25zLCB7IHN1Y2Nlc3M6ICQubm9vcCwgdG9rZW46IHRva2VuIH0pO1xuICAgICAgICAgICAgX3RoaXMuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogdXNlckluZm8udXNlcl9pZCwgdG9rZW46IHRva2VuIH0sIHVzZXJHcm91cE9wdHMpLmRvbmUoIGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGEgPSB7YXV0aDogcmVzcG9uc2UsIHVzZXI6IHVzZXJJbmZvLCB1c2VyR3JvdXBzOiBtZW1iZXJJbmZvLCBncm91cFNlbGVjdGlvbjoge30gfTtcblxuICAgICAgICAgICAgICAgIHZhciBzZXNzaW9uSW5mbyA9IHtcbiAgICAgICAgICAgICAgICAgICAgJ2F1dGhfdG9rZW4nOiB0b2tlbixcbiAgICAgICAgICAgICAgICAgICAgJ2FjY291bnQnOiBhZGFwdGVyT3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgICAgICAncHJvamVjdCc6IGFkYXB0ZXJPcHRpb25zLnByb2plY3QsXG4gICAgICAgICAgICAgICAgICAgICd1c2VySWQnOiB1c2VySW5mby51c2VyX2lkXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAvLyBUaGUgZ3JvdXAgaXMgbm90IHJlcXVpcmVkIGlmIHRoZSB1c2VyIGlzIG5vdCBsb2dnaW5nIGludG8gYSBwcm9qZWN0XG4gICAgICAgICAgICAgICAgaWYgKCFhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHNhdmVTZXNzaW9uKHNlc3Npb25JbmZvLCBfdGhpcy5zdG9yZSk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBncm91cCA9IG51bGw7XG4gICAgICAgICAgICAgICAgaWYgKG1lbWJlckluZm8ubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoZSB1c2VyIGhhcyBubyBncm91cHMgYXNzb2NpYXRlZCBpbiB0aGlzIGFjY291bnQnLCA0MDEsIGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZW1iZXJJbmZvLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTZWxlY3QgdGhlIG9ubHkgZ3JvdXBcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBtZW1iZXJJbmZvWzBdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobWVtYmVySW5mby5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChncm91cElkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmlsdGVyZWRHcm91cHMgPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKHJlc0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc0dyb3VwLmdyb3VwSWQgPT09IGdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gZmlsdGVyZWRHcm91cHMubGVuZ3RoID09PSAxID8gZmlsdGVyZWRHcm91cHNbMF0gOiBudWxsO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBncm91cFNlbGVjdGlvbiA9IGdyb3VwLmdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEuZ3JvdXBTZWxlY3Rpb25bYWRhcHRlck9wdGlvbnMucHJvamVjdF0gPSBncm91cFNlbGVjdGlvbjtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNlc3Npb25JbmZvV2l0aEdyb3VwID0gJC5leHRlbmQoe30sIHNlc3Npb25JbmZvLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAnZ3JvdXBJZCc6IGdyb3VwLmdyb3VwSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAnZ3JvdXBOYW1lJzogZ3JvdXAubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICdpc0ZhYyc6IF9maW5kVXNlckluR3JvdXAoZ3JvdXAubWVtYmVycywgdXNlckluZm8udXNlcl9pZCkucm9sZSA9PT0gJ2ZhY2lsaXRhdG9yJ1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgc2F2ZVNlc3Npb24oc2Vzc2lvbkluZm9XaXRoR3JvdXAsIF90aGlzLnN0b3JlKTtcbiAgICAgICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoaXMgdXNlciBpcyBhc3NvY2lhdGVkIHdpdGggbW9yZSB0aGFuIG9uZSBncm91cC4gUGxlYXNlIHNwZWNpZnkgYSBncm91cCBpZCB0byBsb2cgaW50byBhbmQgdHJ5IGFnYWluJywgNDAzLCBkYXRhKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGhhbmRsZVN1Y2Nlc3M7XG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vIFRyeSB0byBsb2dpbiBhcyBhIHN5c3RlbSB1c2VyXG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuYWNjb3VudCA9IG51bGw7XG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuZXJyb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdChyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIF90aGlzLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuYXV0aEFkYXB0ZXIubG9naW4oYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAqIExvZ3MgdXNlciBvdXQuXG4gICAgKlxuICAgICogKipFeGFtcGxlKipcbiAgICAqXG4gICAgKiAgICAgICBhdXRoTWdyLmxvZ291dCgpO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICovXG4gICAgbG9nb3V0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgYWRhcHRlck9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHRva2VuOiB0b2tlbiB9LCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciByZW1vdmVDb29raWVGbiA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgc3RvcmUucmVtb3ZlKEVQSV9DT09LSUVfS0VZLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICBzdG9yZS5yZW1vdmUoRVBJX1NFU1NJT05fS0VZLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICB0b2tlbiA9ICcnO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhBZGFwdGVyLmxvZ291dChhZGFwdGVyT3B0aW9ucykuZG9uZShyZW1vdmVDb29raWVGbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGV4aXN0aW5nIHVzZXIgYWNjZXNzIHRva2VuIGlmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluLiBPdGhlcndpc2UsIGxvZ3MgdGhlIHVzZXIgaW4sIGNyZWF0aW5nIGEgbmV3IHVzZXIgYWNjZXNzIHRva2VuLCBhbmQgcmV0dXJucyB0aGUgbmV3IHRva2VuLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBhdXRoTWdyLmdldFRva2VuKClcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coJ015IHRva2VuIGlzICcsIHRva2VuKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgaWYgKHRva2VuKSB7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKHRva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICogICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKylcbiAgICAgKiAgICAgICAgICAgICAgICAgIHsgY29uc29sZS5sb2coZ3JvdXBzW2ldLm5hbWUpOyB9XG4gICAgICogICAgICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIHBhcnRpY3VsYXIgdXNlclxuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHt1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB0b2tlbjogc2F2ZWRQcm9qQWNjZXNzVG9rZW4gfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcGFyYW1zYCBPYmplY3Qgd2l0aCBhIHVzZXJJZCBhbmQgdG9rZW4gcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSB1c2VySWQuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBPdGhlcndpc2UsIHBhc3MgYSBzdHJpbmcuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGBwYXJhbXMudG9rZW5gIFRoZSBhdXRob3JpemF0aW9uIGNyZWRlbnRpYWxzIChhY2Nlc3MgdG9rZW4pIHRvIHVzZSBmb3IgY2hlY2tpbmcgdGhlIGdyb3VwcyBmb3IgdGhpcyB1c2VyLiBJZiBsb29raW5nIHVwIGdyb3VwcyBmb3IgdGhlIGN1cnJlbnRseSBsb2dnZWQgaW4gdXNlciwgdGhpcyBpcyBpbiB0aGUgc2Vzc2lvbiBpbmZvcm1hdGlvbi4gQSB0ZWFtIG1lbWJlcidzIHRva2VuIG9yIGEgcHJvamVjdCBhY2Nlc3MgdG9rZW4gY2FuIGFjY2VzcyBhbGwgdGhlIGdyb3VwcyBmb3IgYWxsIGVuZCB1c2VycyBpbiB0aGUgdGVhbSBvciBwcm9qZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKi9cbiAgICBnZXRVc2VyR3JvdXBzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHsgc3VjY2VzczogJC5ub29wIH0sIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAobWVtYmVySW5mbykge1xuICAgICAgICAgICAgLy8gVGhlIG1lbWJlciBBUEkgaXMgYXQgdGhlIGFjY291bnQgc2NvcGUsIHdlIGZpbHRlciBieSBwcm9qZWN0XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICAgICAgICAgIG1lbWJlckluZm8gPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBncm91cC5wcm9qZWN0ID09PSBhZGFwdGVyT3B0aW9ucy5wcm9qZWN0O1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRTdWNjZXNzLmFwcGx5KHRoaXMsIFttZW1iZXJJbmZvXSk7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKG1lbWJlckluZm8pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBtZW1iZXJBZGFwdGVyID0gbmV3IE1lbWJlckFkYXB0ZXIoeyB0b2tlbjogcGFyYW1zLnRva2VuIH0pO1xuICAgICAgICBtZW1iZXJBZGFwdGVyLmdldEdyb3Vwc0ZvclVzZXIocGFyYW1zLCBhZGFwdGVyT3B0aW9ucykuZmFpbCgkZC5yZWplY3QpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHNlc3Npb24gaW5mb3JtYXRpb24gZm9yIHRoZSBjdXJyZW50IHVzZXIsIGluY2x1ZGluZyB0aGUgYHVzZXJJZGAsIGBhY2NvdW50YCwgYHByb2plY3RgLCBgZ3JvdXBJZGAsIGBncm91cE5hbWVgLCBgaXNGYWNgICh3aGV0aGVyIHRoZSBlbmQgdXNlciBpcyBhIGZhY2lsaXRhdG9yIG9mIHRoaXMgZ3JvdXApLCBhbmQgYGF1dGhfdG9rZW5gICh1c2VyIGFjY2VzcyB0b2tlbikuXG4gICAgICpcbiAgICAgKiAqSW1wb3J0YW50KjogVGhpcyBtZXRob2QgaXMgc3luY2hyb25vdXMuIFRoZSBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHJldHVybmVkIGltbWVkaWF0ZWx5IGluIGFuIG9iamVjdDsgbm8gY2FsbGJhY2tzIG9yIHByb21pc2VzIGFyZSBuZWVkZWQuXG4gICAgICpcbiAgICAgKiBCeSBkZWZhdWx0LCBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHN0b3JlZCBpbiBhIGNvb2tpZSBpbiB0aGUgYnJvd3Nlci4gWW91IGNhbiBjaGFuZ2UgdGhpcyB3aXRoIHRoZSBgc3RvcmVgIGNvbmZpZ3VyYXRpb24gb3B0aW9uLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm86IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiBnZXRTZXNzaW9uKHRoaXMuc3RvcmUsIG9wdGlvbnMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEF1dGhNYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2hhbm5lbCA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlJyk7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgYXJvdW5kIHRoZSBkZWZhdWx0IFtjb21ldGQgSmF2YVNjcmlwdCBsaWJyYXJ5XShodHRwOi8vZG9jcy5jb21ldGQub3JnLzIvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCksIGAkLmNvbWV0ZGAuIEl0IHByb3ZpZGVzIGEgZmV3IG5pY2UgZmVhdHVyZXMgdGhhdCBgJC5jb21ldGRgIGRvZXNuJ3QsIGluY2x1ZGluZzpcbiAqXG4gKiAqIEF1dG9tYXRpYyByZS1zdWJzY3JpcHRpb24gdG8gY2hhbm5lbHMgaWYgeW91IGxvc2UgeW91ciBjb25uZWN0aW9uXG4gKiAqIE9ubGluZSAvIE9mZmxpbmUgbm90aWZpY2F0aW9uc1xuICogKiAnRXZlbnRzJyBmb3IgY29tZXRkIG5vdGlmaWNhdGlvbnMgKGluc3RlYWQgb2YgaGF2aW5nIHRvIGxpc3RlbiBvbiBzcGVjaWZpYyBtZXRhIGNoYW5uZWxzKVxuICpcbiAqIFdoaWxlIHlvdSBjYW4gd29yayBkaXJlY3RseSB3aXRoIHRoZSBDaGFubmVsIE1hbmFnZXIgdGhyb3VnaCBOb2RlLmpzIChmb3IgZXhhbXBsZSwgYHJlcXVpcmUoJ21hbmFnZXIvY2hhbm5lbC1tYW5hZ2VyJylgKSAtLSBvciBldmVuIHdvcmsgZGlyZWN0bHkgd2l0aCBgJC5jb21ldGRgIGFuZCBFcGljZW50ZXIncyB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIC0tIG1vc3Qgb2Z0ZW4gaXQgd2lsbCBiZSBlYXNpZXN0IHRvIHdvcmsgd2l0aCB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKS4gVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIHRoYXQgaW5zdGFudGlhdGVzIGEgQ2hhbm5lbCBNYW5hZ2VyIHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgTWFuYWdlci4gKFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLilcbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgTWFuYWdlciBpbiBjbGllbnQtc2lkZSBKYXZhU2NyaXB0LCBpbnN0YW50aWF0ZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSwgZ2V0IHRoZSBjaGFubmVsLCB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gKlxuICogICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAqICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgTWFuYWdlci4gQmVzaWRlcyB0aGUgY29tbW9uIG9wdGlvbnMgbGlzdGVkIGhlcmUsIHNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIG90aGVyIHN1cHBvcnRlZCBvcHRpb25zLlxuICogKiBgb3B0aW9ucy51cmxgIFRoZSBDb21ldGQgZW5kcG9pbnQgVVJMLlxuICogKiBgb3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkYCBXaGV0aGVyIHdlYnNvY2tldCBzdXBwb3J0IGlzIGFjdGl2ZSAoYm9vbGVhbikuXG4gKiAqIGBvcHRpb25zLmNoYW5uZWxgIE90aGVyIGRlZmF1bHRzIHRvIHBhc3Mgb24gdG8gaW5zdGFuY2VzIG9mIHRoZSB1bmRlcmx5aW5nIENoYW5uZWwgU2VydmljZS4gU2VlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pIGZvciBkZXRhaWxzLlxuICpcbiAqL1xudmFyIENoYW5uZWxNYW5hZ2VyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICBpZiAoISQuY29tZXRkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tZXRkIGxpYnJhcnkgbm90IGZvdW5kLiBQbGVhc2UgaW5jbHVkZSBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy51cmwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhbiB1cmwgZm9yIHRoZSBjb21ldGQgc2VydmVyJyk7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbG9nIGxldmVsIGZvciB0aGUgY2hhbm5lbCAobG9ncyB0byBjb25zb2xlKS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGxvZ0xldmVsOiAnaW5mbycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlLiBEZWZhdWx0cyB0byBgZmFsc2VgOyBFcGljZW50ZXIgZG9lc24ndCBjdXJyZW50bHkgc3VwcG9ydCBjb21tdW5pY2F0aW9uIHRocm91Z2ggd2Vic29ja2V0cy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICB3ZWJzb2NrZXRFbmFibGVkOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogSWYgZmFsc2UgZWFjaCBpbnN0YW5jZSBvZiBDaGFubmVsIHdpbGwgaGF2ZSBhIHNlcGFyYXRlIGNvbWV0ZCBjb25uZWN0aW9uIHRvIHNlcnZlciwgd2hpY2ggY291bGQgYmUgbm9pc3kuIFNldCB0byB0cnVlIHRvIHJlLXVzZSB0aGUgc2FtZSBjb25uZWN0aW9uIGFjcm9zcyBpbnN0YW5jZXMuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2hhcmVDb25uZWN0aW9uOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLyksIHdoaWNoIGFyZSBjcmVhdGVkIHRocm91Z2ggYGdldENoYW5uZWwoKWAuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBjaGFubmVsOiB7XG5cbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMgPSBbXTtcbiAgICB0aGlzLm9wdGlvbnMgPSBkZWZhdWx0Q29tZXRPcHRpb25zO1xuXG4gICAgaWYgKGRlZmF1bHRDb21ldE9wdGlvbnMuc2hhcmVDb25uZWN0aW9uICYmIENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkKSB7XG4gICAgICAgIHRoaXMuY29tZXRkID0gQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQ7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICB2YXIgY29tZXRkID0gbmV3ICQuQ29tZXRkKCk7XG4gICAgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQgPSBjb21ldGQ7XG5cbiAgICBjb21ldGQud2Vic29ja2V0RW5hYmxlZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMud2Vic29ja2V0RW5hYmxlZDtcblxuICAgIHRoaXMuaXNDb25uZWN0ZWQgPSBmYWxzZTtcbiAgICB2YXIgY29ubmVjdGlvbkJyb2tlbiA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignZGlzY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIGNvbm5lY3Rpb25TdWNjZWVkZWQgPSBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIoJ2Nvbm5lY3QnLCBtZXNzYWdlKTtcbiAgICB9O1xuICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICBjb21ldGQuY29uZmlndXJlKGRlZmF1bHRDb21ldE9wdGlvbnMpO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9jb25uZWN0JywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgdmFyIHdhc0Nvbm5lY3RlZCA9IHRoaXMuaXNDb25uZWN0ZWQ7XG4gICAgICAgIHRoaXMuaXNDb25uZWN0ZWQgPSAobWVzc2FnZS5zdWNjZXNzZnVsID09PSB0cnVlKTtcbiAgICAgICAgaWYgKCF3YXNDb25uZWN0ZWQgJiYgdGhpcy5pc0Nvbm5lY3RlZCkgeyAvL0Nvbm5lY3RpbmcgZm9yIHRoZSBmaXJzdCB0aW1lXG4gICAgICAgICAgICBjb25uZWN0aW9uU3VjY2VlZGVkLmNhbGwodGhpcywgbWVzc2FnZSk7XG4gICAgICAgIH0gZWxzZSBpZiAod2FzQ29ubmVjdGVkICYmICF0aGlzLmlzQ29ubmVjdGVkKSB7IC8vT25seSB0aHJvdyBkaXNjb25uZWN0ZWQgbWVzc2FnZSBmcm8gdGhlIGZpcnN0IGRpc2Nvbm5lY3QsIG5vdCBvbmNlIHBlciB0cnlcbiAgICAgICAgICAgIGNvbm5lY3Rpb25Ccm9rZW4uY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH0uYmluZCh0aGlzKSk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Rpc2Nvbm5lY3QnLCBjb25uZWN0aW9uQnJva2VuKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvaGFuZHNoYWtlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgaWYgKG1lc3NhZ2Uuc3VjY2Vzc2Z1bCkge1xuICAgICAgICAgICAgLy9odHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0X3N1YnNjcmliZS5odG1sI2phdmFzY3JpcHRfc3Vic2NyaWJlX21ldGFfY2hhbm5lbHNcbiAgICAgICAgICAgIC8vIF4gXCJkeW5hbWljIHN1YnNjcmlwdGlvbnMgYXJlIGNsZWFyZWQgKGxpa2UgYW55IG90aGVyIHN1YnNjcmlwdGlvbikgYW5kIHRoZSBhcHBsaWNhdGlvbiBuZWVkcyB0byBmaWd1cmUgb3V0IHdoaWNoIGR5bmFtaWMgc3Vic2NyaXB0aW9uIG11c3QgYmUgcGVyZm9ybWVkIGFnYWluXCJcbiAgICAgICAgICAgIGNvbWV0ZC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgJChtZS5jdXJyZW50U3Vic2NyaXB0aW9ucykuZWFjaChmdW5jdGlvbiAoaW5kZXgsIHN1YnMpIHtcbiAgICAgICAgICAgICAgICAgICAgY29tZXRkLnJlc3Vic2NyaWJlKHN1YnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vT3RoZXIgaW50ZXJlc3RpbmcgZXZlbnRzIGZvciByZWZlcmVuY2VcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3N1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3N1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWJzY3JpYmUnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCd1bnN1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvcHVibGlzaCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3B1Ymxpc2gnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3Vuc3VjY2Vzc2Z1bCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ2Vycm9yJywgbWVzc2FnZSk7XG4gICAgfSk7XG5cbiAgICBjb21ldGQuaGFuZHNoYWtlKCk7XG5cbiAgICB0aGlzLmNvbWV0ZCA9IGNvbWV0ZDtcbn07XG5cblxuQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgIHZhciBjaGFubmVsID0gY20uZ2V0Q2hhbm5lbCgpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvL0lmIHlvdSBqdXN0IHdhbnQgdG8gcGFzcyBpbiBhIHN0cmluZ1xuICAgICAgICBpZiAob3B0aW9ucyAmJiAhJC5pc1BsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAgICAgdHJhbnNwb3J0OiB0aGlzLmNvbWV0ZFxuICAgICAgICB9O1xuICAgICAgICB2YXIgY2hhbm5lbCA9IG5ldyBDaGFubmVsKCQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLm9wdGlvbnMuY2hhbm5lbCwgZGVmYXVsdHMsIG9wdGlvbnMpKTtcblxuXG4gICAgICAgIC8vV3JhcCBzdWJzIGFuZCB1bnN1YnMgc28gd2UgY2FuIHVzZSBpdCB0byByZS1hdHRhY2ggaGFuZGxlcnMgYWZ0ZXIgYmVpbmcgZGlzY29ubmVjdGVkXG4gICAgICAgIHZhciBzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHN1YmlkID0gc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyAgPSB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmNvbmNhdChzdWJpZCk7XG4gICAgICAgICAgICByZXR1cm4gc3ViaWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuXG4gICAgICAgIHZhciB1bnN1YnMgPSBjaGFubmVsLnVuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnVuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJlbW92ZWQgPSB1bnN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zW2ldLmlkID09PSByZW1vdmVkLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZW1vdmVkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlclxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIChtb3JlIGdlbmVyaWMpIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pLCB0byBpbnN0YW50aWF0ZSBpdCB3aXRoIEVwaWNlbnRlci1zcGVjaWZpYyBkZWZhdWx0cy4gSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGluY2x1ZGluZyBhIG5vdGlmaWNhdGlvbiBvciBjaGF0IGZlYXR1cmUgaW4geW91ciBwcm9qZWN0LCB1c2luZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIHByb2JhYmx5IHRoZSBlYXNpZXN0IHdheSB0byBnZXQgc3RhcnRlZC5cbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXI6IGluc3RhbnRpYXRlIGl0LCBnZXQgdGhlIGNoYW5uZWwgb2YgdGhlIHNjb3BlIHlvdSB3YW50IChbdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLCBvciBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpKSwgdGhlbiB1c2UgdGhlIGNoYW5uZWwncyBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIHN1YnNjcmliZSB0byB0b3BpY3Mgb3IgcHVibGlzaCBkYXRhIHRvIHRvcGljcy5cbiAqXG4gKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAqXG4gKiBGb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIEVwaWNlbnRlcidzIHB1c2ggY2hhbm5lbCwgc2VlIHRoZSBpbnRyb2R1Y3Rvcnkgbm90ZXMgb24gdGhlIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIHBhZ2UuXG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYHNlcnZlcmAgT2JqZWN0IHdpdGggZGV0YWlscyBhYm91dCB0aGUgRXBpY2VudGVyIHByb2plY3QgZm9yIHRoaXMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbnN0YW5jZS5cbiAqICogYHNlcnZlci5hY2NvdW50YCBUaGUgRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgc2VydmVyLnByb2plY3RgIEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICovXG5cbnZhciBDaGFubmVsTWFuYWdlciA9IHJlcXVpcmUoJy4vY2hhbm5lbC1tYW5hZ2VyJyk7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgdXJsU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlJyk7XG5cbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBzZXNzaW9uID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG52YXIgZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvciA9IGZ1bmN0aW9uICh2YWx1ZSwgc2Vzc2lvbktleU5hbWUsIHNldHRpbmdzKSB7XG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgaWYgKHNldHRpbmdzICYmIHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXSkge1xuICAgICAgICAgICAgdmFsdWUgPSBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV07XG4gICAgICAgIH0gZWxzZSBpZiAodXNlckluZm9bc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHVzZXJJbmZvW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihzZXNzaW9uS2V5TmFtZSArICcgbm90IGZvdW5kLiBQbGVhc2UgbG9nLWluIGFnYWluLCBvciBzcGVjaWZ5ICcgKyBzZXNzaW9uS2V5TmFtZSArICcgZXhwbGljaXRseScpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbn07XG52YXIgX19zdXBlciA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZTtcbnZhciBFcGljZW50ZXJDaGFubmVsTWFuYWdlciA9IGNsYXNzRnJvbShDaGFubmVsTWFuYWdlciwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcblxuICAgICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgICAgICBhY2NvdW50OiB1c2VySW5mby5hY2NvdW50LFxuICAgICAgICAgICAgcHJvamVjdDogdXNlckluZm8ucHJvamVjdCxcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIHVzZXJJbmZvLCBvcHRpb25zKTtcblxuICAgICAgICB2YXIgdXJsT3B0cyA9IHVybFNlcnZpY2UoZGVmYXVsdENvbWV0T3B0aW9ucy5zZXJ2ZXIpO1xuICAgICAgICBpZiAoIWRlZmF1bHRDb21ldE9wdGlvbnMudXJsKSB7XG4gICAgICAgICAgICAvL0RlZmF1bHQgZXBpY2VudGVyIGNvbWV0ZCBlbmRwb2ludFxuICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy51cmwgPSB1cmxPcHRzLnByb3RvY29sICsgJzovLycgKyB1cmxPcHRzLmhvc3QgKyAnL2NoYW5uZWwvc3Vic2NyaWJlJztcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgZGVmYXVsdENvbWV0T3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBnaXZlbiBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLiBUaGUgZ3JvdXAgbXVzdCBleGlzdCBpbiB0aGUgYWNjb3VudCAodGVhbSkgYW5kIHByb2plY3QgcHJvdmlkZWQuXG4gICAgICpcbiAgICAgKiBUaGVyZSBhcmUgbm8gbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWw7IGFsbCBtZXNzYWdlcyBhcmUgdXNlci1vcmlnaW5hdGVkLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJ2Jyb2FkY2FzdHMnLCBjYWxsYmFjayk7XG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBHcm91cCB0byBicm9hZGNhc3QgdG8uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldEdyb3VwQ2hhbm5lbDogZnVuY3Rpb24gKGdyb3VwTmFtZSkge1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScpO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2dyb3VwJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lXS5qb2luKCcvJyk7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICogICAgICAgICBydW46IHsgbW9kZWw6ICdtb2RlbC5lcW4nIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICogICAgIHdvcmxkTWFuYWdlci5nZXRDdXJyZW50V29ybGQoKS50aGVuKGZ1bmN0aW9uICh3b3JsZE9iamVjdCwgd29ybGRBZGFwdGVyKSB7XG4gICAgICogICAgICAgICB2YXIgd29ybGRDaGFubmVsID0gY20uZ2V0V29ybGRDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHdvcmxkQ2hhbm5lbC5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICogICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICogICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFRoZSB3b3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFdvcmxkQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCBncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHdvcmxkaWQgPSAoJC5pc1BsYWluT2JqZWN0KHdvcmxkKSAmJiB3b3JsZC5pZCkgPyB3b3JsZC5pZCA6IHdvcmxkO1xuICAgICAgICBpZiAoIXdvcmxkaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgYSB3b3JsZCBpZCcpO1xuICAgICAgICB9XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJyk7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvd29ybGQnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgY3VycmVudCBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaW4gdGhhdCB1c2VyJ3MgY3VycmVudCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS4gTm90ZSB0aGF0IHRoaXMgY2hhbm5lbCBvbmx5IGdldHMgbm90aWZpY2F0aW9ucyBmb3Igd29ybGRzIGN1cnJlbnRseSBpbiBtZW1vcnkuIChTZWUgbW9yZSBiYWNrZ3JvdW5kIG9uIFtwZXJzaXN0ZW5jZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlKS4pXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB1c2VyQ2hhbm5lbCA9IGNtLmdldFVzZXJDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHVzZXJDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFVzZXJDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXIsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVzZXJpZCA9ICgkLmlzUGxhaW5PYmplY3QodXNlcikgJiYgdXNlci5pZCkgPyB1c2VyLmlkIDogdXNlcjtcbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkLCB1c2VyaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIHRoYXQgYXV0b21hdGljYWxseSB0cmFja3MgdGhlIHByZXNlbmNlIG9mIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhhdCBpcywgd2hldGhlciB0aGUgZW5kIHVzZXIgaXMgY3VycmVudGx5IG9ubGluZSBpbiB0aGlzIGdyb3VwIGFuZCB3b3JsZC4gTm90aWZpY2F0aW9ucyBhcmUgYXV0b21hdGljYWxseSBzZW50IHdoZW4gdGhlIGVuZCB1c2VyIGNvbWVzIG9ubGluZSwgYW5kIHdoZW4gdGhlIGVuZCB1c2VyIGdvZXMgb2ZmbGluZSAobm90IHByZXNlbnQgZm9yIG1vcmUgdGhhbiAyIG1pbnV0ZXMpLiBVc2VmdWwgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZm9yIGxldHRpbmcgZWFjaCBlbmQgdXNlciBrbm93IHdoZXRoZXIgb3RoZXIgdXNlcnMgaW4gdGhlaXIgc2hhcmVkIHdvcmxkIGFyZSBhbHNvIG9ubGluZS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIG1vZGVsOiAnbW9kZWwuZXFuJ1xuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZFNlcnZpY2UpIHtcbiAgICAgKiAgICAgICAgIHZhciBwcmVzZW5jZUNoYW5uZWwgPSBjbS5nZXRQcmVzZW5jZUNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgcHJlc2VuY2VDaGFubmVsLm9uKCdwcmVzZW5jZScsIGZ1bmN0aW9uIChldnQsIG5vdGlmaWNhdGlvbikge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZyhub3RpZmljYXRpb24ub25saW5lLCBub3RpZmljYXRpb24udXNlcklkKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB3b3JsZGAgV29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB1c2VyaWRgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFByZXNlbmNlQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCB1c2VyaWQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgdmFyIGxhc3RQaW5nVGltZSA9IHsgfTtcblxuICAgICAgICB2YXIgUElOR19JTlRFUlZBTCA9IDYwMDA7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCdpbnRlcm5hbC1waW5nLWNoYW5uZWwnLCBmdW5jdGlvbiAobm90aWZpY2F0aW9uKSB7XG4gICAgICAgICAgICB2YXIgaW5jb21pbmdVc2VySWQgPSBub3RpZmljYXRpb24uZGF0YS51c2VyO1xuICAgICAgICAgICAgaWYgKCFsYXN0UGluZ1RpbWVbaW5jb21pbmdVc2VySWRdICYmIGluY29taW5nVXNlcklkICE9PSB1c2VyaWQpIHtcbiAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDogaW5jb21pbmdVc2VySWQsIG9ubGluZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIHsgdXNlcjogdXNlcmlkIH0pO1xuXG4gICAgICAgICAgICAkLmVhY2gobGFzdFBpbmdUaW1lLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBub3cgPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSAmJiB2YWx1ZSArIChQSU5HX0lOVEVSVkFMICogMikgPCBub3cpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2tleV0gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDoga2V5LCBvbmxpbmU6IGZhbHNlIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBQSU5HX0lOVEVSVkFMKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIGNvbGxlY3Rpb24uIChUaGUgY29sbGVjdGlvbiBuYW1lIGlzIHNwZWNpZmllZCBpbiB0aGUgYHJvb3RgIGFyZ3VtZW50IHdoZW4gdGhlIFtEYXRhIFNlcnZpY2VdKC4uL2RhdGEtYXBpLXNlcnZpY2UvKSBpcyBpbnN0YW50aWF0ZWQuKSBNdXN0IGJlIG9uZSBvZiB0aGUgY29sbGVjdGlvbnMgaW4gdGhpcyBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBhdXRvbWF0aWMgbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWwgd2hlbiBkYXRhIGlzIGNyZWF0ZWQsIHVwZGF0ZWQsIG9yIGRlbGV0ZWQgaW4gdGhpcyBjb2xsZWN0aW9uLiBTZWUgbW9yZSBvbiBbYXV0b21hdGljIG1lc3NhZ2VzIHRvIHRoZSBkYXRhIGNoYW5uZWxdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNkYXRhLW1lc3NhZ2VzKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZ2MgPSBjbS5nZXREYXRhQ2hhbm5lbCgnc3VydmV5LXJlc3BvbnNlcycpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEsIG1ldGEpIHtcbiAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIG1ldGEuZGF0ZSBpcyB0aW1lIG9mIGNoYW5nZSxcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnN1YlR5cGUgaXMgdGhlIGtpbmQgb2YgY2hhbmdlOiBuZXcsIHVwZGF0ZSwgb3IgZGVsZXRlXG4gICAgICogICAgICAgICAgLy8gbWV0YS5wYXRoIGlzIHRoZSBmdWxsIHBhdGggdG8gdGhlIGNoYW5nZWQgZGF0YVxuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKG1ldGEpO1xuICAgICAqICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgY29sbGVjdGlvbmAgTmFtZSBvZiBjb2xsZWN0aW9uIHdob3NlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIHlvdSB3YW50IHRvIHJlY2VpdmUuXG4gICAgICovXG4gICAgZ2V0RGF0YUNoYW5uZWw6IGZ1bmN0aW9uIChjb2xsZWN0aW9uKSB7XG4gICAgICAgIGlmICghY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIGNvbGxlY3Rpb24gdG8gbGlzdGVuIG9uLicpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2RhdGEnLCBhY2NvdW50LCBwcm9qZWN0LCBjb2xsZWN0aW9uXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgLy9UT0RPOiBGaXggYWZ0ZXIgRXBpY2VudGVyIGJ1ZyBpcyByZXNvbHZlZFxuICAgICAgICB2YXIgb2xkc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjYWxsYmFja1dpdGhDbGVhbkRhdGEgPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgICAgICAgICAgICAgIHZhciBtZXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYXlsb2FkLmNoYW5uZWwsXG4gICAgICAgICAgICAgICAgICAgIHN1YlR5cGU6IHBheWxvYWQuZGF0YS5zdWJUeXBlLFxuICAgICAgICAgICAgICAgICAgICBkYXRlOiBwYXlsb2FkLmRhdGEuZGF0ZVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGFjdHVhbERhdGEgPSBwYXlsb2FkLmRhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICBpZiAoYWN0dWFsRGF0YS5kYXRhKSB7IC8vRGVsZXRlIG5vdGlmaWNhdGlvbnMgYXJlIG9uZSBkYXRhLWxldmVsIGJlaGluZCBvZiBjb3Vyc2VcbiAgICAgICAgICAgICAgICAgICAgYWN0dWFsRGF0YSA9IGFjdHVhbERhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIGFjdHVhbERhdGEsIG1ldGEpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aENsZWFuRGF0YSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVQSV9DT09LSUVfS0VZOiAnZXBpY2VudGVyLnByb2plY3QudG9rZW4nLFxuICAgIEVQSV9TRVNTSU9OX0tFWTogJ2VwaWNlbnRlci51c2VyLnNlc3Npb24nLFxuICAgIFNUUkFURUdZX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLXNjZW5hcmlvJ1xufTsiLCIvKipcbiogIyMgUnVuIE1hbmFnZXJcbipcbiogVGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBhY2Nlc3MgdG8gcnVucyBmb3IgeW91ciBwcm9qZWN0LiBUaGlzIGFsbG93cyB5b3UgdG8gcmVhZCBhbmQgdXBkYXRlIHZhcmlhYmxlcywgY2FsbCBvcGVyYXRpb25zLCBldGMuIEFkZGl0aW9uYWxseSwgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLiBTcGVjaWZpY2FsbHksIHlvdSBjYW4gc2VsZWN0IFtydW4gY3JlYXRpb24gc3RyYXRlZ2llcyAocnVsZXMpXSguLi8uLi9zdHJhdGVneS8pIGZvciB3aGljaCBydW5zIGVuZCB1c2VycyBvZiB5b3VyIHByb2plY3Qgd29yayB3aXRoIHdoZW4gdGhleSBsb2cgaW4gdG8geW91ciBwcm9qZWN0LlxuKlxuKiBUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGNyZWF0ZSBuZXcgcnVucywgaW5jbHVkaW5nIHRoZSBFcGljZW50ZXIuanMgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSwgdGhlIFJFU0ZUZnVsIFtSdW4gQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkpIGFuZCB0aGUgW01vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLykuIEhvd2V2ZXIsIGZvciBzb21lIHByb2plY3RzIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gcGljayB1cCB3aGVyZSB0aGUgdXNlciBsZWZ0IG9mZiwgdXNpbmcgYW4gZXhpc3RpbmcgcnVuLiBBbmQgaW4gc29tZSBwcm9qZWN0cywgd2hldGhlciB0byBjcmVhdGUgYSBuZXcgcnVuIG9yIHVzZSBhbiBleGlzdGluZyBvbmUgaXMgY29uZGl0aW9uYWwsIGZvciBleGFtcGxlIGJhc2VkIG9uIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZXhpc3RpbmcgcnVuIG9yIHlvdXIgb3duIGtub3dsZWRnZSBhYm91dCB0aGUgbW9kZWwuIFRoZSBSdW4gTWFuYWdlciBwcm92aWRlcyB0aGlzIGxldmVsIG9mIGNvbnRyb2w6IHlvdXIgY2FsbCB0byBgZ2V0UnVuKClgLCByYXRoZXIgdGhhbiBhbHdheXMgcmV0dXJuaW5nIGEgbmV3IHJ1biwgcmV0dXJucyBhIHJ1biBiYXNlZCBvbiB0aGUgc3RyYXRlZ3kgeW91J3ZlIHNwZWNpZmllZC4gKE5vdGUgdGhhdCBtYW55IG9mIHRoZSBFcGljZW50ZXIgc2FtcGxlIHByb2plY3RzIHVzZSBhIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LCBiZWNhdXNlIGdlbmVyYWxseSB0aGUgc2FtcGxlIHByb2plY3RzIGFyZSBwbGF5ZWQgaW4gb25lIGVuZCB1c2VyIHNlc3Npb24gYW5kIGRvbid0IGNhcmUgYWJvdXQgcnVuIHN0YXRlcyBvciBydW4gc3RyYXRlZ2llcy4pXG4qXG4qXG4qICMjIyBVc2luZyB0aGUgUnVuIE1hbmFnZXIgdG8gY3JlYXRlIGFuZCBhY2Nlc3MgcnVuc1xuKlxuKiBUbyB1c2UgdGhlIFJ1biBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuKlxuKiAgICogYHJ1bmA6IChyZXF1aXJlZCkgUnVuIG9iamVjdC4gTXVzdCBjb250YWluOlxuKiAgICAgICAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICAgICAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4qICAgICAgICogYG1vZGVsYDogVGhlIG5hbWUgb2YgeW91ciBwcmltYXJ5IG1vZGVsIGZpbGUuIChTZWUgbW9yZSBvbiBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4pXG4qICAgICAgICogYHNjb3BlYDogKG9wdGlvbmFsKSBTY29wZSBvYmplY3QgZm9yIHRoZSBydW4sIGZvciBleGFtcGxlIGBzY29wZS5ncm91cGAgd2l0aCB2YWx1ZSBvZiB0aGUgbmFtZSBvZiB0aGUgZ3JvdXAuXG4qICAgICAgICogYHNlcnZlcmA6IChvcHRpb25hbCkgQW4gb2JqZWN0IHdpdGggb25lIGZpZWxkLCBgaG9zdGAuIFRoZSB2YWx1ZSBvZiBgaG9zdGAgaXMgdGhlIHN0cmluZyBgYXBpLmZvcmlvLmNvbWAsIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4qICAgICAgICogYGZpbGVzYDogKG9wdGlvbmFsKSBJZiBhbmQgb25seSBpZiB5b3UgYXJlIHVzaW5nIGEgVmVuc2ltIG1vZGVsIGFuZCB5b3UgaGF2ZSBhZGRpdGlvbmFsIGRhdGEgdG8gcGFzcyBpbiB0byB5b3VyIG1vZGVsLCB5b3UgY2FuIHBhc3MgYSBgZmlsZXNgIG9iamVjdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgZmlsZXMsIGZvciBleGFtcGxlOiBgXCJmaWxlc1wiOiB7XCJkYXRhXCI6IFwibXlFeHRyYURhdGEueGxzXCJ9YC4gKE5vdGUgdGhhdCB5b3UnbGwgYWxzbyBuZWVkIHRvIGFkZCB0aGlzIHNhbWUgZmlsZXMgb2JqZWN0IHRvIHlvdXIgVmVuc2ltIFtjb25maWd1cmF0aW9uIGZpbGVdKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltLykuKSBTZWUgdGhlIFt1bmRlcmx5aW5nIE1vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLyNwb3N0LWNyZWF0aW5nLWEtbmV3LXJ1bi1mb3ItdGhpcy1wcm9qZWN0KSBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbi5cbipcbiogICAqIGBzdHJhdGVneWA6IChvcHRpb25hbCkgUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4qXG4qICAgKiBgc2Vzc2lvbktleWA6IChvcHRpb25hbCkgTmFtZSBvZiBicm93c2VyIGNvb2tpZSBpbiB3aGljaCB0byBzdG9yZSBydW4gaW5mb3JtYXRpb24sIGluY2x1ZGluZyBydW4gaWQuIE1hbnkgY29uZGl0aW9uYWwgc3RyYXRlZ2llcywgaW5jbHVkaW5nIHRoZSBwcm92aWRlZCBzdHJhdGVnaWVzLCByZWx5IG9uIHRoaXMgYnJvd3NlciBjb29raWUgdG8gc3RvcmUgdGhlIHJ1biBpZCBhbmQgaGVscCBtYWtlIHRoZSBkZWNpc2lvbiBvZiB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZS4gVGhlIG5hbWUgb2YgdGhpcyBjb29raWUgZGVmYXVsdHMgdG8gYGVwaWNlbnRlci1zY2VuYXJpb2AgYW5kIGNhbiBiZSBzZXQgd2l0aCB0aGUgYHNlc3Npb25LZXlgIHBhcmFtZXRlci5cbipcbipcbiogQWZ0ZXIgaW5zdGFudGlhdGluZyBhIFJ1biBNYW5hZ2VyLCBtYWtlIGEgY2FsbCB0byBgZ2V0UnVuKClgIHdoZW5ldmVyIHlvdSBuZWVkIHRvIGFjY2VzcyBhIHJ1biBmb3IgdGhpcyBlbmQgdXNlci4gVGhlIGBSdW5NYW5hZ2VyLnJ1bmAgY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLiBUaGUgUnVuIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBhY2Nlc3MgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy5cbipcbiogKipFeGFtcGxlKipcbipcbiogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiogICAgICAgICAgIHJ1bjoge1xuKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJyxcbiogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiogICAgICAgICAgIH0sXG4qICAgICAgICAgICBzdHJhdGVneTogJ2Fsd2F5cy1uZXcnLFxuKiAgICAgICAgICAgc2Vzc2lvbktleTogJ2VwaWNlbnRlci1zZXNzaW9uJ1xuKiAgICAgICB9KTtcbiogICAgICAgcm0uZ2V0UnVuKClcbiogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuKiAgICAgICAgICAgICAgIC8vIHRoZSByZXR1cm4gdmFsdWUgb2YgZ2V0UnVuKCkgaXMgYSBydW4gb2JqZWN0XG4qICAgICAgICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gYWxzbyBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuKiAgICAgICAgICAgICAgIC8vIHNvIGFueSBSdW4gU2VydmljZSBtZXRob2QgaXMgdmFsaWQgaGVyZVxuKiAgICAgICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiogICAgICAgfSlcbipcbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBzdHJhdGVnaWVzTWFwID0gcmVxdWlyZSgnLi9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcCcpO1xudmFyIHNwZWNpYWxPcGVyYXRpb25zID0gcmVxdWlyZSgnLi9zcGVjaWFsLW9wZXJhdGlvbnMnKTtcbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcblxuXG5mdW5jdGlvbiBwYXRjaFJ1blNlcnZpY2Uoc2VydmljZSwgbWFuYWdlcikge1xuICAgIGlmIChzZXJ2aWNlLnBhdGNoZWQpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuXG4gICAgdmFyIG9yaWcgPSBzZXJ2aWNlLmRvO1xuICAgIHNlcnZpY2UuZG8gPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHJlc2VydmVkT3BzID0gT2JqZWN0LmtleXMoc3BlY2lhbE9wZXJhdGlvbnMpO1xuICAgICAgICBpZiAocmVzZXJ2ZWRPcHMuaW5kZXhPZihvcGVyYXRpb24pID09PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG9yaWcuYXBwbHkoc2VydmljZSwgYXJndW1lbnRzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT3BlcmF0aW9uc1tvcGVyYXRpb25dLmNhbGwoc2VydmljZSwgcGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBzZXJ2aWNlLnBhdGNoZWQgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHNlcnZpY2U7XG59XG5cblxuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cblxuICAgIHN0cmF0ZWd5OiAnbmV3LWlmLWluaXRpYWxpemVkJ1xufTtcblxuZnVuY3Rpb24gUnVuTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMucnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICB0aGlzLnJ1biA9IHRoaXMub3B0aW9ucy5ydW47XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5ydW4gPSBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMucnVuKTtcbiAgICB9XG5cbiAgICBwYXRjaFJ1blNlcnZpY2UodGhpcy5ydW4sIHRoaXMpO1xuXG4gICAgdmFyIFN0cmF0ZWd5Q3RvciA9IHR5cGVvZiB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgPT09ICdmdW5jdGlvbicgPyB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgOiBzdHJhdGVnaWVzTWFwW3RoaXMub3B0aW9ucy5zdHJhdGVneV07XG5cbiAgICBpZiAoIVN0cmF0ZWd5Q3Rvcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NwZWNpZmllZCBydW4gY3JlYXRpb24gc3RyYXRlZ3kgd2FzIGludmFsaWQ6JywgdGhpcy5vcHRpb25zLnN0cmF0ZWd5KTtcbiAgICB9XG5cbiAgICB0aGlzLnN0cmF0ZWd5ID0gbmV3IFN0cmF0ZWd5Q3Rvcih0aGlzLnJ1biwgdGhpcy5vcHRpb25zKTtcbn1cblxuUnVuTWFuYWdlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSAnZ29vZCcgcnVuLlxuICAgICAqXG4gICAgICogQSBnb29kIHJ1biBpcyBkZWZpbmVkIGJ5IHRoZSBzdHJhdGVneS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBzdHJhdGVneSBpcyBgYWx3YXlzLW5ld2AsIHRoZSBjYWxsXG4gICAgICogdG8gYGdldFJ1bigpYCBhbHdheXMgcmV0dXJucyBhIG5ld2x5IGNyZWF0ZWQgcnVuOyBpZiB0aGUgc3RyYXRlZ3kgaXMgYG5ldy1pZi1wZXJzaXN0ZWRgLFxuICAgICAqIGBnZXRSdW4oKWAgY3JlYXRlcyBhIG5ldyBydW4gaWYgdGhlIHByZXZpb3VzIHJ1biBpcyBpbiBhIHBlcnNpc3RlZCBzdGF0ZSwgb3RoZXJ3aXNlXG4gICAgICogaXQgcmV0dXJucyB0aGUgcHJldmlvdXMgcnVuLiBTZWUgW1J1biBNYW5hZ2VyIFN0cmF0ZWdpZXNdKC4uLy4uL3N0cmF0ZWd5LykgZm9yIG1vcmUgb24gc3RyYXRlZ2llcy5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5nZXRSdW4oKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqIEByZXR1cm4geyRwcm9taXNlfSBQcm9taXNlIHRvIGNvbXBsZXRlIHRoZSBjYWxsLlxuICAgICAqL1xuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdHJhdGVneVxuICAgICAgICAgICAgICAgIC5nZXRSdW4oKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSBuZXcgcnVuLCByZWdhcmRsZXNzIG9mIHN0cmF0ZWd5OiBmb3JjZSBjcmVhdGlvbiBvZiBhIG5ldyBydW4uXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgcm0ucmVzZXQoKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIChuZXcpIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBydW5TZXJ2aWNlT3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgUnVuIFNlcnZpY2UuIFNlZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBmb3IgbW9yZS5cbiAgICAgKi9cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5LnJlc2V0KHJ1blNlcnZpY2VPcHRpb25zKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJ1bk1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIC8vIGFsd2F5cyBjcmVhdGUgYSBuZXcgcnVuIVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1ha2VTZXEgPSByZXF1aXJlKCcuLi8uLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFNlc3Npb25TdG9yZSA9IHJlcXVpcmUoJy4uLy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBVcmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgc2Vzc2lvblN0b3JlID0gbmV3IFNlc3Npb25TdG9yZSh7fSk7XG52YXIgdXJsU2VydmljZSA9IG5ldyBVcmxTZXJ2aWNlKCk7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9rZXktbmFtZXMnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHNlc3Npb25LZXk6IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZLFxuICAgIHBhdGg6ICcnXG59O1xuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBwYXRoKSB7XG4gICAgaWYgKCFwYXRoKSB7XG4gICAgICAgIGlmICghdXJsU2VydmljZS5pc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgICAgICBwYXRoID0gJy8nICsgW3VybFNlcnZpY2UuYXBwUGF0aCwgdXJsU2VydmljZS5hY2NvdW50UGF0aCwgdXJsU2VydmljZS5wcm9qZWN0UGF0aF0uam9pbignLycpO1xuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHdlIGRvbid0IGdldCBjb25zZWN1dGVpdmUgJy8nIHNvIHdlIGhhdmUgYSB2YWxpZCBwYXRoIGZvciB0aGUgc2Vzc2lvblxuICAgICAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZSgvXFwvezIsfS9nLCcvJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYXRoID0gJyc7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gc2V0IHRoZSBzZWVzaW9uS2V5IGZvciB0aGUgcnVuXG4gICAgc2Vzc2lvblN0b3JlLnNldChzZXNzaW9uS2V5LCBKU09OLnN0cmluZ2lmeSh7IHJ1bklkOiBydW4uaWQgfSksIHsgcm9vdDogcGF0aCB9KTtcbn1cblxuLyoqXG4qIENvbmRpdGlvbmFsIENyZWF0aW9uIFN0cmF0ZWd5XG4qIFRoaXMgc3RyYXRlZ3kgd2lsbCB0cnkgdG8gZ2V0IHRoZSBydW4gc3RvcmVkIGluIHRoZSBjb29raWUgYW5kXG4qIGV2YWx1YXRlIGlmIG5lZWRzIHRvIGNyZWF0ZSBhIG5ldyBydW4gYnkgY2FsbGluZyB0aGUgJ2NvbmRpdGlvbicgZnVuY3Rpb25cbiovXG5cbi8qIGpzaGludCBlcW51bGw6IHRydWUgKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KHJ1blNlcnZpY2UsIGNvbmRpdGlvbiwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChjb25kaXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb25kaXRpb25hbCBzdHJhdGVneSBuZWVkcyBhIGNvbmRpdGlvbiB0byBjcmVhdGV0ZSBhIHJ1bicpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fYXV0aCA9IG5ldyBBdXRoTWFuYWdlcigpO1xuICAgICAgICB0aGlzLnJ1biA9IG1ha2VTZXEocnVuU2VydmljZSk7XG4gICAgICAgIHRoaXMuY29uZGl0aW9uID0gdHlwZW9mIGNvbmRpdGlvbiAhPT0gJ2Z1bmN0aW9uJyA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNvbmRpdGlvbjsgfSA6IGNvbmRpdGlvbjtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9LFxuXG4gICAgcnVuT3B0aW9uc1dpdGhTY29wZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdXNlclNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiB1c2VyU2Vzc2lvbi5ncm91cE5hbWUgfVxuICAgICAgICB9LCB0aGlzLnJ1bk9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBvcHQgPSB0aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5ydW5cbiAgICAgICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgc2V0UnVuSW5TZXNzaW9uKF90aGlzLm9wdGlvbnMuc2Vzc2lvbktleSwgcnVuLCBfdGhpcy5vcHRpb25zLnBhdGgpO1xuICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmUuZ2V0KHRoaXMub3B0aW9ucy5zZXNzaW9uS2V5KSk7XG5cbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRBbmRDaGVjayhydW5TZXNzaW9uKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgX2xvYWRBbmRDaGVjazogZnVuY3Rpb24gKHJ1blNlc3Npb24pIHtcbiAgICAgICAgdmFyIHNob3VsZENyZWF0ZSA9IGZhbHNlO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1blxuICAgICAgICAgICAgLmxvYWQocnVuU2Vzc2lvbi5ydW5JZCwgbnVsbCwge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uIChydW4sIG1zZywgaGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBzaG91bGRDcmVhdGUgPSBfdGhpcy5jb25kaXRpb24uY2FsbChfdGhpcywgcnVuLCBoZWFkZXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIGlmIChzaG91bGRDcmVhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9wdCA9IF90aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgbmVlZCB0byBkbyB0aGlzLCBvbiB0aGUgb3JpZ2luYWwgcnVuU2VydmljZSAoaWUgbm90IHNlcXVlbmNpYWxpemVkKVxuICAgICAgICAgICAgICAgICAgICAvLyBzbyB3ZSBkb24ndCBnZXQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1bi5vcmlnaW5hbC5jcmVhdGUob3B0KVxuICAgICAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oX3RoaXMub3B0aW9ucy5zZXNzaW9uS2V5LCBydW4pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnN0YXJ0KCk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSAgPSBydW5TZXJ2aWNlO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSBuZXdseSBjcmVhdGVkIHJ1blxuICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoKS5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSh0aGlzLnJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vaWRlbnRpdHktc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0b3JlOiB7XG4gICAgICAgIHN5bmNocm9ub3VzOiB0cnVlXG4gICAgfVxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcblxuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMud29ybGRBcGkgPSBuZXcgV29ybGRBcGlBZGFwdGVyKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciB3b3JsZEFwaSA9IHRoaXMud29ybGRBcGk7XG4gICAgICAgIHZhciBtb2RlbCA9IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAoIWN1clVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDAsIGVycm9yOiAnV2UgbmVlZCBhbiBhdXRoZW50aWNhdGVkIHVzZXIgdG8gam9pbiBhIG11bHRpcGxheWVyIHdvcmxkLiAoRVJSOiBubyB1c2VySWQgaW4gc2Vzc2lvbiknIH0sIHNlc3Npb24pLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsb2FkUnVuRnJvbVdvcmxkID0gZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDQsIGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IGluIGFueSB3b3JsZC4nIH0sIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oX3RoaXMuX2xvYWRSdW4pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgZHRkLnJlamVjdChlcnJvciwgc2Vzc2lvbiwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIF9sb2FkUnVuOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIFN0YXRlQXBpID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICAgICAgdGhpcy5fc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICAgICAgdGhpcy5zdGF0ZUFwaSA9IG5ldyBTdGF0ZUFwaSgpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZEFuZENoZWNrID0gdGhpcy5fbG9hZEFuZENoZWNrLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVSdW4gPSB0aGlzLl9yZXN0b3JlUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2dldEFsbFJ1bnMgPSB0aGlzLl9nZXRBbGxSdW5zLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0QWxsUnVucygpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9sb2FkQW5kQ2hlY2spO1xuICAgIH0sXG5cbiAgICBfZ2V0QWxsUnVuczogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2UodGhpcy5fc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9Jyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5xdWVyeSh7XG4gICAgICAgICAgICAndXNlci5pZCc6IHNlc3Npb24udXNlcklkIHx8ICcwMDAwJyxcbiAgICAgICAgICAgICdzY29wZS5ncm91cCc6IHNlc3Npb24uZ3JvdXBOYW1lXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVucykge1xuICAgICAgICBpZiAoIXJ1bnMgfHwgIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGVDb21wID0gZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIuZGF0ZSkgLSBuZXcgRGF0ZShhLmRhdGUpOyB9O1xuICAgICAgICB2YXIgbGF0ZXN0UnVuID0gcnVucy5zb3J0KGRhdGVDb21wKVswXTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHNob3VsZFJlcGxheSA9IGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGxhdGVzdFJ1bi5pZCwgbnVsbCwge1xuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVwbGF5ID0gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2hvdWxkUmVwbGF5ID8gX3RoaXMuX3Jlc3RvcmVSdW4ocnVuLmlkKSA6IHJ1bjtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9yZXN0b3JlUnVuOiBmdW5jdGlvbiAocnVuSWQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVBcGkucmVwbGF5KHsgcnVuSWQ6IHJ1bklkIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJ1bihyZXNwLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW4ubG9hZChpZCwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgICduZXctaWYtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLFxuICAgICduZXctaWYtcGVyc2lzdGVkJzogcmVxdWlyZSgnLi9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1taXNzaW5nJzogcmVxdWlyZSgnLi9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpLFxuICAgICdhbHdheXMtbmV3JzogcmVxdWlyZSgnLi9hbHdheXMtbmV3LXN0cmF0ZWd5JyksXG4gICAgJ211bHRpcGxheWVyJzogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdwZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXInOiByZXF1aXJlKCcuL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneScpLFxuICAgICdub25lJzogcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgdmFsaWRGaWx0ZXI6IHsgc2F2ZWQ6IHRydWUgfVxufTtcblxuZnVuY3Rpb24gU2NlbmFyaW9NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMucnVuU2VydmljZSA9IHRoaXMub3B0aW9ucy5ydW4gfHwgbmV3IFJ1blNlcnZpY2UodGhpcy5vcHRpb25zKTtcbn1cblxuU2NlbmFyaW9NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy52YWxpZEZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlcik7XG4gICAgfSxcblxuICAgIGxvYWRWYXJpYWJsZXM6IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UucXVlcnkodGhpcy5maWx0ZXIsIHsgaW5jbHVkZTogdmFycyB9KTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgbWV0YSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2VydmljZShydW4pLnNhdmUoJC5leHRlbmQodHJ1ZSwge30sIHsgc2F2ZWQ6IHRydWUgfSwgbWV0YSkpO1xuICAgIH0sXG5cbiAgICBhcmNoaXZlOiBmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSh7IHNhdmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuXG4gICAgX2dldFNlcnZpY2U6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW4gfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdvYmplY3QnICYmIHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NhdmUgbWV0aG9kIHJlcXVpcmVzIGEgcnVuIHNlcnZpY2Ugb3IgYSBydW5JZCcpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW5JZCB9KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICByZXNldDogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucywgbWFuYWdlcikge1xuICAgICAgICByZXR1cm4gbWFuYWdlci5yZXNldChvcHRpb25zKTtcbiAgICB9XG59O1xuIiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9ICByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG4vLyB2YXIgZGVmYXVsdHMgPSB7XG4vLyAgYWNjb3VudDogJycsXG4vLyAgcHJvamVjdDogJycsXG4vLyAgZ3JvdXA6ICcnLFxuLy8gIHRyYW5zcG9ydDoge1xuLy8gIH1cbi8vIH07XG5cblxuZnVuY3Rpb24gYnVpbGRTdHJhdGVneSh3b3JsZElkLCBkdGQpIHtcblxuICAgIHJldHVybiBmdW5jdGlvbiBDdG9yKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICAkLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm90IGltcGxlbWVudGQuIE5lZWQgYXBpIGNoYW5nZXMnKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlLmNhbGwodGhpcywgcnVuLCBfdGhpcy5ydW5TZXJ2aWNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcklkYCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSBncm91cCBmb3IgdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bih7bW9kZWw6ICdteU1vZGVsLnB5J30pXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBtb2RlbGAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgbW9kZWwgZmlsZS4gUmVxdWlyZWQgaWYgbm90IGFscmVhZHkgcGFzc2VkIGluIGFzIGBydW4ubW9kZWxgIHdoZW4gdGhlIFdvcmxkIE1hbmFnZXIgaXMgY3JlYXRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgX3RoaXMub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJtLmdldFJ1bigpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHJ1biwgcm0ucnVuU2VydmljZSwgcm0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5nZXRDdXJyZW50V29ybGQoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bik7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIGFwaSk7XG59O1xuIiwiLyoqXG4gKiAjI0ZpbGUgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGlzIGlzIHVzZWQgdG8gdXBsb2FkL2Rvd25sb2FkIGZpbGVzIGRpcmVjdGx5IG9udG8gRXBpY2VudGVyLCBhbmFsb2dvdXMgdG8gdXNpbmcgdGhlIEZpbGUgTWFuYWdlciBVSSBpbiBFcGljZW50ZXIgZGlyZWN0bHkgb3IgU0ZUUGluZyBmaWxlcyBpbi4gVGhlIEFzc2V0IEFQSSBpcyB0eXBpY2FsbHkgdXNlZCBmb3IgYWxsIHByb2plY3QgdXNlLWNhc2VzLCBhbmQgaXQncyB1bmxpa2VseSB0aGlzIEZpbGUgU2VydmljZSB3aWxsIGJlIHVzZWQgZGlyZWN0bHkgZXhjZXB0IGJ5IEFkbWluIHRvb2xzIChlLmcuIEZsb3cgSW5zcGVjdG9yKS5cbiAqXG4gKiBQYXJ0aWFsbHkgaW1wbGVtZW50ZWQuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCBzdG9yZS5nZXQoJ2VwaWNlbnRlci50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZmlsZScpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQXN5bmNBUEkgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgYSBkaXJlY3RvcnkgbGlzdGluZywgb3IgY29udGVudHMgb2YgYSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGZpbGVQYXRoYCAgIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZm9sZGVyVHlwZWAgT25lIG9mIE1vZGVsfFN0YXRpY3xOb2RlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBnZXRDb250ZW50czogZnVuY3Rpb24gKGZpbGVQYXRoLCBmb2xkZXJUeXBlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IGZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbi8vIHZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGtleU5hbWVzID0gcmVxdWlyZSgnLi4vbWFuYWdlcnMva2V5LW5hbWVzJyk7XG5cbnZhciBhcGlFbmRwb2ludCA9ICdhc3NldCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZShzdG9yZS5nZXQoa2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZKSB8fCAne30nKTtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9DT09LSUVfS0VZKSB8fCAnJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gRGVmYXVsdHMgdG8gc2Vzc2lvbidzIGBncm91cE5hbWVgLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogc2Vzc2lvbi51c2VySWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgc2NvcGUgZm9yIHRoZSBhc3NldC4gVmFsaWQgdmFsdWVzIGFyZTogYHVzZXJgLCBgZ3JvdXBgLCBhbmQgYHByb2plY3RgLiBTZWUgYWJvdmUgZm9yIHRoZSByZXF1aXJlZCBwZXJtaXNzaW9ucyB0byB3cml0ZSB0byBlYWNoIHNjb3BlLiBEZWZhdWx0cyB0byBgdXNlcmAsIG1lYW5pbmcgdGhlIGN1cnJlbnQgZW5kIHVzZXIgb3IgYSBmYWNpbGl0YXRvciBpbiB0aGUgZW5kIHVzZXIncyBncm91cCBjYW4gZWRpdCB0aGUgYXNzZXQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBzY29wZTogJ3VzZXInLFxuICAgICAgICAvKipcbiAgICAgICAgICogRGV0ZXJtaW5lcyBpZiBhIHJlcXVlc3QgdG8gbGlzdCB0aGUgYXNzZXRzIGluIGEgc2NvcGUgaW5jbHVkZXMgdGhlIGNvbXBsZXRlIFVSTCBmb3IgZWFjaCBhc3NldCAoYHRydWVgKSwgb3Igb25seSB0aGUgZmlsZSBuYW1lcyBvZiB0aGUgYXNzZXRzIChgZmFsc2VgKS4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGZ1bGxVcmw6IHRydWUsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgdHJhbnNwb3J0IG9iamVjdCBjb250YWlucyB0aGUgb3B0aW9ucyBwYXNzZWQgdG8gdGhlIFhIUiByZXF1ZXN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7XG4gICAgICAgICAgICBwcm9jZXNzRGF0YTogZmFsc2VcbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIGFzc2V0QXBpUGFyYW1zID0gWydlbmNvZGluZycsICdkYXRhJywgJ2NvbnRlbnRUeXBlJ107XG4gICAgdmFyIHNjb3BlQ29uZmlnID0ge1xuICAgICAgICB1c2VyOiBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSxcbiAgICAgICAgZ3JvdXA6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10sXG4gICAgICAgIHByb2plY3Q6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0J10sXG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZUZpbGVuYW1lID0gZnVuY3Rpb24gKGZpbGVuYW1lKSB7XG4gICAgICAgIGlmICghZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZmlsZW5hbWUgaXMgbmVlZGVkLicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZVVybFBhcmFtcyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICBpZiAoIXBhcnRLZXlzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Njb3BlIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cblxuICAgICAgICAkLmVhY2gocGFydEtleXMsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICghb3B0aW9uc1t0aGlzXSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzICsgJyBwYXJhbWV0ZXIgaXMgbmVlZGVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgdmFyIGJ1aWxkVXJsID0gZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgIHZhbGlkYXRlVXJsUGFyYW1zKG9wdGlvbnMpO1xuICAgICAgICB2YXIgcGFydEtleXMgPSBzY29wZUNvbmZpZ1tvcHRpb25zLnNjb3BlXTtcbiAgICAgICAgdmFyIHBhcnRzID0gJC5tYXAocGFydEtleXMsIGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zW2tleV07XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgcHJldmVudHMgYWRkaW5nIGEgdHJhaWxpbmcgLyBpbiB0aGUgVVJMIGFzIHRoZSBBc3NldCBBUElcbiAgICAgICAgICAgIC8vIGRvZXMgbm90IHdvcmsgY29ycmVjdGx5IHdpdGggaXRcbiAgICAgICAgICAgIGZpbGVuYW1lID0gJy8nICsgZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHBhcnRzLmpvaW4oJy8nKSArIGZpbGVuYW1lO1xuICAgIH07XG5cbiAgICAvLyBQcml2YXRlIGZ1bmN0aW9uLCBhbGwgcmVxdWVzdHMgZm9sbG93IGEgbW9yZSBvciBsZXNzIHNhbWUgYXBwcm9hY2ggdG9cbiAgICAvLyB1c2UgdGhlIEFzc2V0IEFQSSBhbmQgdGhlIGRpZmZlcmVuY2UgaXMgdGhlIEhUVFAgdmVyYlxuICAgIC8vXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBtZXRob2RgIChSZXF1aXJlZCkgSFRUUCB2ZXJiXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS9yZXBsYWNlL2NyZWF0ZVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUElcbiAgICAvLyBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgdmFyIHVwbG9hZCA9IGZ1bmN0aW9uIChtZXRob2QsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVGaWxlbmFtZShmaWxlbmFtZSk7XG4gICAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgcGFyYW1ldGVyIGlzIGNsZWFuXG4gICAgICAgIG1ldGhvZCA9IG1ldGhvZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB2YXIgY29udGVudFR5cGUgPSBwYXJhbXMgaW5zdGFuY2VvZiBGb3JtRGF0YSA9PT0gdHJ1ZSA/IGZhbHNlIDogJ2FwcGxpY2F0aW9uL2pzb24nO1xuICAgICAgICBpZiAoY29udGVudFR5cGUgPT09ICdhcHBsaWNhdGlvbi9qc29uJykge1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIGFzc2V0QXBpUGFyYW1zKTtcbiAgICAgICAgfSBlbHNlIHsgLy8gZWxzZSB3ZSdyZSBzZW5kaW5nIGZvcm0gZGF0YSB3aGljaCBnb2VzIGRpcmVjdGx5IGluIHJlcXVlc3QgYm9keVxuICAgICAgICAgICAgLy8gRm9yIG11bHRpcGFydC9mb3JtLWRhdGEgdXBsb2FkcyB0aGUgZmlsZW5hbWUgaXMgbm90IHNldCBpbiB0aGUgVVJMLFxuICAgICAgICAgICAgLy8gaXQncyBnZXR0aW5nIHBpY2tlZCBieSB0aGUgRm9ybURhdGEgZmllbGQgZmlsZW5hbWUuXG4gICAgICAgICAgICBmaWxlbmFtZSA9IG1ldGhvZCA9PT0gJ3Bvc3QnIHx8IG1ldGhvZCA9PT0gJ3B1dCcgPyAnJyA6IGZpbGVuYW1lO1xuICAgICAgICB9XG4gICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCwgY29udGVudFR5cGU6IGNvbnRlbnRUeXBlIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwW21ldGhvZF0ocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS4gVGhlIHNlcnZlciByZXR1cm5zIGFuIGVycm9yIChzdGF0dXMgY29kZSBgNDA5YCwgY29uZmxpY3QpIGlmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLCBzb1xuICAgICAgICAqIGNoZWNrIGZpcnN0IHdpdGggYSBgbGlzdCgpYCBvciBhIGBnZXQoKWAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBhYSA9IG5ldyBGLnNlcnZpY2UuQXNzZXQoe1xuICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAgICAqICAgICAgICAgIHVzZXJJZDogJydcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAgICAgICAgKiAgICAgICBhYS5jcmVhdGUoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gICAgICAgICogICAgICAgICAgIGNvbnRlbnRUeXBlOiAndGV4dC9wbGFpbidcbiAgICAgICAgKiAgICAgICB9LCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyBhbHRlcm5hdGl2ZWx5LCBjcmVhdGUgYSBuZXcgYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJ1cGxvYWQtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5VcGxvYWQgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3VwbG9hZC1maWxlJykub24oJ3N1Ym1pdCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLmNyZWF0ZShmaWxlbmFtZSwgZGF0YSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gY3JlYXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUEkuIFJlcXVpcmVkIGlmIHRoZSBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYCwgb3RoZXJ3aXNlIGlnbm9yZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZW5jb2RpbmdgIEVpdGhlciBgSEVYYCBvciBgQkFTRV82NGAuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmRhdGFgIFRoZSBlbmNvZGVkIGRhdGEgZm9yIHRoZSBmaWxlLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5jb250ZW50VHlwZWAgVGhlIG1pbWUgdHlwZSBvZiB0aGUgZmlsZS4gT3B0aW9uYWwuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3Bvc3QnLCBmaWxlbmFtZSwgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGEgZmlsZSBmcm9tIHRoZSBBc3NldCBBUEksIGZldGNoaW5nIHRoZSBhc3NldCBjb250ZW50LiAoVG8gZ2V0IGEgbGlzdFxuICAgICAgICAqIG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZSwgdXNlIGBsaXN0KClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byByZXRyaWV2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBnZXRTZXJ2aWNlT3B0aW9ucyA9IF9waWNrKHNlcnZpY2VPcHRpb25zLCBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSk7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBnZXRTZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBsaXN0IG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5saXN0KHsgZnVsbFVybDogdHJ1ZSB9KS50aGVuKGZ1bmN0aW9uKGZpbGVMaXN0KXtcbiAgICAgICAgKiAgICAgICAgICAgY29uc29sZS5sb2coJ2FycmF5IG9mIGZpbGVzID0gJywgZmlsZUxpc3QpO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5zY29wZWAgKE9wdGlvbmFsKSBUaGUgc2NvcGUgKGB1c2VyYCwgYGdyb3VwYCwgYHByb2plY3RgKS5cbiAgICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGBvcHRpb25zLmZ1bGxVcmxgIChPcHRpb25hbCkgRGV0ZXJtaW5lcyBpZiB0aGUgbGlzdCBvZiBhc3NldHMgaW4gYSBzY29wZSBpbmNsdWRlcyB0aGUgY29tcGxldGUgVVJMIGZvciBlYWNoIGFzc2V0IChgdHJ1ZWApLCBvciBvbmx5IHRoZSBmaWxlIG5hbWVzIG9mIHRoZSBhc3NldHMgKGBmYWxzZWApLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybCgnJywgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuICAgICAgICAgICAgdmFyIGZ1bGxVcmwgPSBnZXRPcHRpb25zLmZ1bGxVcmw7XG5cbiAgICAgICAgICAgIGlmICghZnVsbFVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZnVsbFBhdGhGaWxlcyA9ICQubWFwKGZpbGVzLCBmdW5jdGlvbiAoZmlsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoZnVsbFBhdGhGaWxlcywgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlcGxhY2VzIGFuIGV4aXN0aW5nIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyByZXBsYWNlIGFuIGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLnJlcGxhY2UoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhObFkyOXVaQ0IwWlhOMElHWnBiR1V1JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJyZXBsYWNlLWZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwicmVwbGFjZS1maWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5SZXBsYWNlIG15RmlsZTwvYnV0dG9uPlxuICAgICAgICAqICAgICAgIC8vIDwvZm9ybT5cbiAgICAgICAgKiAgICAgICAvL1xuICAgICAgICAqICAgICAgICQoJyNyZXBsYWNlLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI3JlcGxhY2UtZmlsZW5hbWUnKS52YWwoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICAgICAgICAqICAgICAgICAgIGRhdGEuYXBwZW5kKCdmaWxlJywgaW5wdXRDb250cm9sLmZpbGVzWzBdLCBmaWxlbmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICBhYS5yZXBsYWNlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgYmVpbmcgcmVwbGFjZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgcmVwbGFjZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3B1dCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5kZWxldGUoc2FtcGxlRmlsZU5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ2RlbGV0ZScsIGZpbGVuYW1lLCB7fSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYXNzZXRVcmw6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlIHByb3ZpZGVzIG1ldGhvZHMgZm9yIGxvZ2dpbmcgaW4gYW5kIGxvZ2dpbmcgb3V0LiBPbiBsb2dpbiwgdGhpcyBzZXJ2aWNlIGNyZWF0ZXMgYW5kIHJldHVybnMgYSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAqXG4gKiBVc2VyIGFjY2VzcyB0b2tlbnMgYXJlIHJlcXVpcmVkIGZvciBlYWNoIGNhbGwgdG8gRXBpY2VudGVyLiAoU2VlIFtQcm9qZWN0IEFjY2Vzc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4pXG4gKlxuICogSWYgeW91IG5lZWQgYWRkaXRpb25hbCBmdW5jdGlvbmFsaXR5IC0tIHN1Y2ggYXMgdHJhY2tpbmcgc2Vzc2lvbiBpbmZvcm1hdGlvbiwgZWFzaWx5IHJldHJpZXZpbmcgdGhlIHVzZXIgdG9rZW4sIG9yIGdldHRpbmcgdGhlIGdyb3VwcyB0byB3aGljaCBhbiBlbmQgdXNlciBiZWxvbmdzIC0tIGNvbnNpZGVyIHVzaW5nIHRoZSBbQXV0aG9yaXphdGlvbiBNYW5hZ2VyXSguLi9hdXRoLW1hbmFnZXIvKSBpbnN0ZWFkLlxuICpcbiAqICAgICAgdmFyIGF1dGggPSBuZXcgRi5zZXJ2aWNlLkF1dGgoKTtcbiAqICAgICAgYXV0aC5sb2dpbih7IHVzZXJOYW1lOiAnanNtaXRoQGFjbWVzaW11bGF0aW9ucy5jb20nLFxuICogICAgICAgICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyB9KTtcbiAqICAgICAgYXV0aC5sb2dvdXQoKTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VyTmFtZTogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFzc3dvcmQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gUmVxdWlyZWQgaWYgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdhdXRoZW50aWNhdGlvbicpXG4gICAgfSk7XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvZ3MgdXNlciBpbiwgcmV0dXJuaW5nIHRoZSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAgICAgICAgICpcbiAgICAgICAgICogSWYgbm8gYHVzZXJOYW1lYCBvciBgcGFzc3dvcmRgIHdlcmUgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLCB0aGV5IGFyZSByZXF1aXJlZCBpbiB0aGUgYG9wdGlvbnNgIGhlcmUuIElmIG5vIGBhY2NvdW50YCB3YXMgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zIGFuZCB0aGUgYHVzZXJOYW1lYCBpcyBmb3IgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGUgYGFjY291bnRgIGlzIHJlcXVpcmVkIGFzIHdlbGwuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgYXV0aC5sb2dpbih7XG4gICAgICAgICAqICAgICAgICAgIHVzZXJOYW1lOiAnanNtaXRoJyxcbiAgICAgICAgICogICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcsXG4gICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyB9KVxuICAgICAgICAgKiAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhcInVzZXIgYWNjZXNzIHRva2VuIGlzOiBcIiwgdG9rZW4uYWNjZXNzX3Rva2VuKTtcbiAgICAgICAgICogICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHN1Y2Nlc3M6ICQubm9vcCB9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBpZiAoIWh0dHBPcHRpb25zLnVzZXJOYW1lIHx8ICFodHRwT3B0aW9ucy5wYXNzd29yZCkge1xuICAgICAgICAgICAgICAgIHZhciByZXNwID0geyBzdGF0dXM6IDQwMSwgc3RhdHVzTWVzc2FnZTogJ05vIHVzZXJuYW1lIG9yIHBhc3N3b3JkIHNwZWNpZmllZC4nIH07XG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvci5jYWxsKHRoaXMsIHJlc3ApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVqZWN0KHJlc3ApLnByb21pc2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHBvc3RQYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgdXNlck5hbWU6IGh0dHBPcHRpb25zLnVzZXJOYW1lLFxuICAgICAgICAgICAgICAgIHBhc3N3b3JkOiBodHRwT3B0aW9ucy5wYXNzd29yZCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoaHR0cE9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vcGFzcyBpbiBudWxsIGZvciBhY2NvdW50IHVuZGVyIG9wdGlvbnMgaWYgeW91IGRvbid0IHdhbnQgaXQgdG8gYmUgc2VudFxuICAgICAgICAgICAgICAgIHBvc3RQYXJhbXMuYWNjb3VudCA9IGh0dHBPcHRpb25zLmFjY291bnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocG9zdFBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2dzIHVzZXIgb3V0IGZyb20gc3BlY2lmaWVkIGFjY291bnRzLlxuICAgICAgICAgKiBFcGljZW50ZXIgbG9nb3V0IGlzIG5vdCBpbXBsZW1lbnRlZCB5ZXQsIGFkZGVkIGEgZHVtbXkgcHJvbWlzZSB0aGF0IGdldHMgYXV0b21hdGljYWxseSByZXNvbHZlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBhdXRoLmxvZ291dCgpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2dvdXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgZHRkLnJlc29sdmUoKTtcbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqICMjIENoYW5uZWwgU2VydmljZVxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBDaGFubmVsIFNlcnZpY2UgaXMgYSBidWlsZGluZyBibG9jayBmb3IgdGhpcyBmdW5jdGlvbmFsaXR5LiBJdCBjcmVhdGVzIGEgcHVibGlzaC1zdWJzY3JpYmUgb2JqZWN0LCBhbGxvd2luZyB5b3UgdG8gcHVibGlzaCBtZXNzYWdlcywgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzLCBvciB1bnN1YnNjcmliZSBmcm9tIG1lc3NhZ2VzIGZvciBhIGdpdmVuICd0b3BpYycgb24gYSBgJC5jb21ldGRgIHRyYW5zcG9ydCBpbnN0YW5jZS5cbiAqXG4gKiBUeXBpY2FsbHksIHlvdSB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgdG8gY3JlYXRlIG9yIHJldHJpZXZlIGNoYW5uZWxzLCB0aGVuIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gbGlzdGVuIHRvIG9yIHVwZGF0ZSBkYXRhLiAoRm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZCBvbiBFcGljZW50ZXIncyBwdXNoIGNoYW5uZWwsIHNlZSB0aGUgaW50cm9kdWN0b3J5IG5vdGVzIG9uIHRoZSBbUHVzaCBDaGFubmVsIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvKSBwYWdlLilcbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UuIFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLlxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCwgdGhlbiBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbiAqXG4gKiAgICAgICAgdmFyIGNzID0gbmV3IEYuc2VydmljZS5DaGFubmVsKCk7XG4gKiAgICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgU2VydmljZSBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgU2VydmljZS5cbiAqICogYG9wdGlvbnMuYmFzZWAgVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLnRvcGljUmVzb2x2ZXJgIEEgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgYWxsICd0b3BpY3MnIHBhc3NlZCBpbnRvIHRoZSBgcHVibGlzaGAgYW5kIGBzdWJzY3JpYmVgIG1ldGhvZHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGltcGxlbWVudCB5b3VyIG93biBzZXJpYWxpemUgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGN1c3RvbSBvYmplY3RzIHRvIHRvcGljIG5hbWVzLiBSZXR1cm5zIGEgU3RyaW5nLiBCeSBkZWZhdWx0LCBpdCBqdXN0IGVjaG9lcyB0aGUgdG9waWMuXG4gKiAqIGBvcHRpb25zLnRyYW5zcG9ydGAgVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLiBTZWUgaHR0cDovL2RvY3MuY29tZXRkLm9yZy9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gY29tZXRkLlxuICovXG52YXIgQ2hhbm5lbCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYmFzZSB0b3BpYy4gVGhpcyBpcyBhZGRlZCBhcyBhIHByZWZpeCB0byBhbGwgZnVydGhlciB0b3BpY3MgeW91IHB1Ymxpc2ggb3Igc3Vic2NyaWJlIHRvIHdoaWxlIHdvcmtpbmcgd2l0aCB0aGlzIENoYW5uZWwgU2VydmljZS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGJhc2U6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqIGB0b3BpY2AgVG9waWMgdG8gcGFyc2UuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiAqU3RyaW5nKjogVGhpcyBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIGEgc3RyaW5nIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICB0b3BpY1Jlc29sdmVyOiBmdW5jdGlvbiAodG9waWMpIHtcbiAgICAgICAgICAgIHJldHVybiB0b3BpYztcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiBudWxsXG4gICAgfTtcbiAgICB0aGlzLmNoYW5uZWxPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbn07XG5cbnZhciBtYWtlTmFtZSA9IGZ1bmN0aW9uIChjaGFubmVsTmFtZSwgdG9waWMpIHtcbiAgICAvL1JlcGxhY2UgdHJhaWxpbmcvZG91YmxlIHNsYXNoZXNcbiAgICB2YXIgbmV3TmFtZSA9IChjaGFubmVsTmFtZSA/IChjaGFubmVsTmFtZSArICcvJyArIHRvcGljKSA6IHRvcGljKS5yZXBsYWNlKC9cXC9cXC8vZywgJy8nKS5yZXBsYWNlKC9cXC8kLywnJyk7XG4gICAgcmV0dXJuIG5ld05hbWU7XG59O1xuXG5cbkNoYW5uZWwucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbC5wcm90b3R5cGUsIHtcblxuICAgIC8vIGZ1dHVyZSBmdW5jdGlvbmFsaXR5OlxuICAgIC8vICAgICAgLy8gU2V0IHRoZSBjb250ZXh0IGZvciB0aGUgY2FsbGJhY2tcbiAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgZnVuY3Rpb24gKCkgeyB0aGlzLmlubmVySFRNTCA9ICdUcmlnZ2VyZWQnfSwgZG9jdW1lbnQuYm9keSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gQ29udHJvbCB0aGUgb3JkZXIgb2Ygb3BlcmF0aW9ucyBieSBzZXR0aW5nIHRoZSBgcHJpb3JpdHlgXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4nLCBjYiwgdGhpcywge3ByaW9yaXR5OiA5fSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIDUwXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiA1MH0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBncmVhdGVyIHRoYW4gNTBcbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6ICc+NTAnfSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIGV2ZW5cbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6IGZ1bmN0aW9uICh2YWwpIHtyZXR1cm4gdmFsICUgMiA9PT0gMH19KTtcblxuXG4gICAgLyoqXG4gICAgICogU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqIFRoZSB0b3BpYyBzaG91bGQgaW5jbHVkZSB0aGUgZnVsbCBwYXRoIG9mIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cyksIHByb2plY3QgaWQsIGFuZCBncm91cCBuYW1lLiAoSW4gbW9zdCBjYXNlcywgaXQgaXMgc2ltcGxlciB0byB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgaW5zdGVhZCwgaW4gd2hpY2ggY2FzZSB0aGlzIGlzIGNvbmZpZ3VyZWQgZm9yIHlvdS4pXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlcyoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjYiA9IGZ1bmN0aW9uKHZhbCkgeyBjb25zb2xlLmxvZyh2YWwuZGF0YSk7IH07XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9wLWxldmVsICdydW4nIHRvcGljXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGNoaWxkcmVuIG9mIHRoZSAncnVuJyB0b3BpYy4gTm90ZSB0aGlzIHdpbGwgYWxzbyBiZSB0cmlnZ2VyZWQgZm9yIGNoYW5nZXMgdG8gcnVuLngueS56LlxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuLyonLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGJvdGggdGhlIHRvcC1sZXZlbCAncnVuJyB0b3BpYyBhbmQgaXRzIGNoaWxkcmVuXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoWycvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJyxcbiAgICAgKiAgICAgICAgICAnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJ10sIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSBwYXJ0aWN1bGFyIHZhcmlhYmxlXG4gICAgICogICAgICBzdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzL3ByaWNlJywgY2IpO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpTdHJpbmcqIFJldHVybnMgYSB0b2tlbiB5b3UgY2FuIGxhdGVyIHVzZSB0byB1bnN1YnNjcmliZS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfEFycmF5fSAgIGB0b3BpY2AgICAgTGlzdCBvZiB0b3BpY3MgdG8gbGlzdGVuIGZvciBjaGFuZ2VzIG9uLlxuICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBgY2FsbGJhY2tgIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGV4ZWN1dGUuIENhbGxiYWNrIGlzIGNhbGxlZCB3aXRoIHNpZ25hdHVyZSBgKGV2dCwgcGF5bG9hZCwgbWV0YWRhdGEpYC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgYGNvbnRleHRgICBDb250ZXh0IGluIHdoaWNoIHRoZSBgY2FsbGJhY2tgIGlzIGV4ZWN1dGVkLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gICBgb3B0aW9uc2AgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICogQHBhcmFtICB7TnVtYmVyfSAgIGBvcHRpb25zLnByaW9yaXR5YCAgVXNlZCB0byBjb250cm9sIG9yZGVyIG9mIG9wZXJhdGlvbnMuIERlZmF1bHRzIHRvIDAuIENhbiBiZSBhbnkgK3ZlIG9yIC12ZSBudW1iZXIuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE51bWJlcnxGdW5jdGlvbn0gICBgb3B0aW9ucy52YWx1ZWAgVGhlIGBjYWxsYmFja2AgaXMgb25seSB0cmlnZ2VyZWQgaWYgdGhpcyBjb25kaXRpb24gbWF0Y2hlcy4gU2VlIGV4YW1wbGVzIGZvciBkZXRhaWxzLlxuICAgICAqXG4gICAgICovXG4gICAgc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9waWMsIGNhbGxiYWNrLCBjb250ZXh0LCBvcHRpb25zKSB7XG5cbiAgICAgICAgdmFyIHRvcGljcyA9IFtdLmNvbmNhdCh0b3BpYyk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBzdWJzY3JpcHRpb25JZHMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuICAgICAgICBvcHRzLnRyYW5zcG9ydC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkLmVhY2godG9waWNzLCBmdW5jdGlvbiAoaW5kZXgsIHRvcGljKSB7XG4gICAgICAgICAgICAgICAgdG9waWMgPSBtYWtlTmFtZShvcHRzLmJhc2UsIG9wdHMudG9waWNSZXNvbHZlcih0b3BpYykpO1xuICAgICAgICAgICAgICAgIHN1YnNjcmlwdGlvbklkcy5wdXNoKG9wdHMudHJhbnNwb3J0LnN1YnNjcmliZSh0b3BpYywgY2FsbGJhY2spKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChzdWJzY3JpcHRpb25JZHNbMV0gPyBzdWJzY3JpcHRpb25JZHMgOiBzdWJzY3JpcHRpb25JZHNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBQdWJsaXNoIGRhdGEgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICAvLyBTZW5kIGRhdGEgdG8gYWxsIHN1YnNjcmliZXJzIG9mIHRoZSAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsIHsgY29tcGxldGVkOiBmYWxzZSB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bi92YXJpYWJsZXMnIHRvcGljXG4gICAgICogICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcycsIHsgcHJpY2U6IDUwIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRvcGljYCBUb3BpYyB0byBwdWJsaXNoIHRvLlxuICAgICAqIEBwYXJhbSAgeyp9IGBkYXRhYCAgRGF0YSB0byBwdWJsaXNoIHRvIHRvcGljLlxuICAgICAqXG4gICAgICovXG4gICAgcHVibGlzaDogZnVuY3Rpb24gKHRvcGljLCBkYXRhKSB7XG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgcmV0dXJuT2JqcyA9IFtdO1xuICAgICAgICB2YXIgb3B0cyA9IG1lLmNoYW5uZWxPcHRpb25zO1xuXG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBpZiAodG9waWMuY2hhckF0KHRvcGljLmxlbmd0aCAtIDEpID09PSAnKicpIHtcbiAgICAgICAgICAgICAgICAgICAgdG9waWMgPSB0b3BpYy5yZXBsYWNlKC9cXCorJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdZb3UgY2FuIGNhbm5vdCBwdWJsaXNoIHRvIGNoYW5uZWxzIHdpdGggd2lsZGNhcmRzLiBQdWJsaXNoaW5nIHRvICcsIHRvcGljLCAnaW5zdGVhZCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpzLnB1c2gob3B0cy50cmFuc3BvcnQucHVibGlzaCh0b3BpYywgZGF0YSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKHJldHVybk9ianNbMV0gPyByZXR1cm5PYmpzIDogcmV0dXJuT2Jqc1swXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVuc3Vic2NyaWJlIGZyb20gY2hhbmdlcyB0byBhIHRvcGljLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgY3MudW5zdWJzY3JpYmUoJ3NhbXBsZVRva2VuJyk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRva2VuYCBUaGUgdG9rZW4gZm9yIHRvcGljIGlzIHJldHVybmVkIHdoZW4geW91IGluaXRpYWxseSBzdWJzY3JpYmUuIFBhc3MgaXQgaGVyZSB0byB1bnN1YnNjcmliZSBmcm9tIHRoYXQgdG9waWMuXG4gICAgICovXG4gICAgdW5zdWJzY3JpYmU6IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICB0aGlzLmNoYW5uZWxPcHRpb25zLnRyYW5zcG9ydC51bnN1YnNjcmliZSh0b2tlbik7XG4gICAgICAgIHJldHVybiB0b2tlbjtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICpcbiAgICAgKiBTdXBwb3J0ZWQgZXZlbnRzIGFyZTogYGNvbm5lY3RgLCBgZGlzY29ubmVjdGAsIGBzdWJzY3JpYmVgLCBgdW5zdWJzY3JpYmVgLCBgcHVibGlzaGAsIGBlcnJvcmAuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqL1xuICAgIG9uOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vbi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdG9wIGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqL1xuICAgIG9mZjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub2ZmLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZXZlbnRzIGFuZCBleGVjdXRlIGhhbmRsZXJzLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqL1xuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENoYW5uZWw7XG4iLCIvKipcbiAqIEBjbGFzcyBDb25maWd1cmF0aW9uU2VydmljZVxuICpcbiAqIEFsbCBzZXJ2aWNlcyB0YWtlIGluIGEgY29uZmlndXJhdGlvbiBzZXR0aW5ncyBvYmplY3QgdG8gY29uZmlndXJlIHRoZW1zZWx2ZXMuIEEgSlMgaGFzaCB7fSBpcyBhIHZhbGlkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCBidXQgb3B0aW9uYWxseSB5b3UgY2FuIHVzZSB0aGUgY29uZmlndXJhdGlvbiBzZXJ2aWNlIHRvIHRvZ2dsZSBjb25maWdzIGJhc2VkIG9uIHRoZSBlbnZpcm9ubWVudFxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgdmFyIGNzID0gcmVxdWlyZSgnY29uZmlndXJhdGlvbi1zZXJ2aWNlJykoe1xuICogICAgICAgICAgZGV2OiB7IC8vZW52aXJvbm1lbnRcbiAgICAgICAgICAgICAgICBwb3J0OiAzMDAwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdsb2NhbGhvc3QnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHByb2Q6IHtcbiAgICAgICAgICAgICAgICBwb3J0OiA4MDgwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgICAgICAgICBsb2dMZXZlbDogJ25vbmUnXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbG9nTGV2ZWw6ICdERUJVRycgLy9nbG9iYWxcbiAqICAgICB9KTtcbiAqXG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudignZGV2Jyk7XG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudigncHJvZCcpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnbm9uZSdcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHVybFNlcnZpY2UgPSByZXF1aXJlKCcuL3VybC1jb25maWctc2VydmljZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IEVudmlyb25tZW50c1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgbG9nTGV2ZWw6ICdOT05FJ1xuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHNlcnZpY2VPcHRpb25zLnNlcnZlciA9IHVybFNlcnZpY2Uoc2VydmljZU9wdGlvbnMuc2VydmVyKTtcblxuICAgIHJldHVybiB7XG5cbiAgICAgICAgZGF0YTogc2VydmljZU9wdGlvbnMsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgZW52aXJvbm1lbnQga2V5IHRvIGdldCBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbVxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGVudlxuICAgICAgICAgKi9cbiAgICAgICAgc2V0RW52OiBmdW5jdGlvbiAoZW52KSB7XG5cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHByb3BlcnR5IG9wdGlvbmFsXG4gICAgICAgICAqIEByZXR1cm4geyp9ICAgICAgICAgIFZhbHVlIG9mIHByb3BlcnR5IGlmIHNwZWNpZmllZCwgdGhlIGVudGlyZSBjb25maWcgb2JqZWN0IG90aGVyd2lzZVxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9uc1twcm9wZXJ0eV07XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5IGlmIGEga2V5IGlzIHByb3ZpZGVkLCBzZXQgYSBrZXkgdG8gdGhhdCB2YWx1ZS4gT3RoZXJ3aXNlIG1lcmdlIG9iamVjdCB3aXRoIGN1cnJlbnQgY29uZmlnXG4gICAgICAgICAqIEBwYXJhbSAgeyp9IHZhbHVlICB2YWx1ZSBmb3IgcHJvdmlkZWQga2V5XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9uc1trZXldID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9O1xufTtcblxuIiwiLyoqXG4gKiAjI0RhdGEgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgRGF0YSBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgbWFuaXB1bGF0ZSBkYXRhIHJlbGF0ZWQgdG8gYW55IG9mIHlvdXIgcHJvamVjdHMuIERhdGEgYXJlIG9yZ2FuaXplZCBpbiBjb2xsZWN0aW9ucy4gRWFjaCBjb2xsZWN0aW9uIGNvbnRhaW5zIGEgZG9jdW1lbnQ7IGVhY2ggZWxlbWVudCBvZiB0aGlzIHRvcC1sZXZlbCBkb2N1bWVudCBpcyBhIEpTT04gb2JqZWN0LiAoU2VlIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gb24gdGhlIHVuZGVybHlpbmcgW0RhdGEgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvZGF0YV9hcGkvKS4pXG4gKlxuICogQWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgRGF0YSBBUEkgU2VydmljZSBkZWZhdWx0cy4gSW4gcGFydGljdWxhciwgdGhlcmUgYXJlIHRocmVlIHJlcXVpcmVkIHBhcmFtZXRlcnMgd2hlbiB5b3UgaW5zdGFudGlhdGUgdGhlIERhdGEgU2VydmljZTpcbiAqXG4gKiAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgcHJvamVjdGA6IEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICogKiBgcm9vdGA6IFRoZSB0aGUgbmFtZSBvZiB0aGUgY29sbGVjdGlvbi4gSWYgeW91IGhhdmUgbXVsdGlwbGUgY29sbGVjdGlvbnMgd2l0aGluIGVhY2ggb2YgeW91ciBwcm9qZWN0cywgeW91IGNhbiBhbHNvIHBhc3MgdGhlIGNvbGxlY3Rpb24gbmFtZSBhcyBhbiBvcHRpb24gZm9yIGVhY2ggY2FsbC5cbiAqXG4gKiAgICAgICB2YXIgZHMgPSBuZXcgRi5zZXJ2aWNlLkRhdGEoe1xuICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgIHJvb3Q6ICdzdXJ2ZXktcmVzcG9uc2VzJyxcbiAqICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBkcy5zYXZlQXMoJ3VzZXIxJyxcbiAqICAgICAgICAgIHsgJ3F1ZXN0aW9uMSc6IDIsICdxdWVzdGlvbjInOiAxMCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiBmYWxzZSwgJ3F1ZXN0aW9uNCc6ICdzb21ldGltZXMnIH0gKTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjInLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMywgJ3F1ZXN0aW9uMic6IDgsXG4gKiAgICAgICAgICAncXVlc3Rpb24zJzogdHJ1ZSwgJ3F1ZXN0aW9uNCc6ICdhbHdheXMnIH0gKTtcbiAqICAgICAgIGRzLnF1ZXJ5KCcnLHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICpcbiAqIE5vdGUgdGhhdCBpbiBhZGRpdGlvbiB0byB0aGUgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgcm9vdGAsIHRoZSBEYXRhIFNlcnZpY2UgcGFyYW1ldGVycyBvcHRpb25hbGx5IGluY2x1ZGUgYSBgc2VydmVyYCBvYmplY3QsIHdob3NlIGBob3N0YCBmaWVsZCBjb250YWlucyB0aGUgVVJJIG9mIHRoZSBGb3JpbyBzZXJ2ZXIuIFRoaXMgaXMgYXV0b21hdGljYWxseSBzZXQsIGJ1dCB5b3UgY2FuIHBhc3MgaXQgZXhwbGljaXRseSBpZiBkZXNpcmVkLiBJdCBpcyBtb3N0IGNvbW1vbmx5IHVzZWQgZm9yIGNsYXJpdHkgd2hlbiB5b3UgYXJlIFtob3N0aW5nIGFuIEVwaWNlbnRlciBwcm9qZWN0IG9uIHlvdXIgb3duIHNlcnZlcl0oLi4vLi4vLi4vaG93X3RvL3NlbGZfaG9zdGluZy8pLlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogTmFtZSBvZiBjb2xsZWN0aW9uLiBEZWZhdWx0cyB0byBgL2AsIHRoYXQgaXMsIHRoZSByb290IGxldmVsIG9mIHlvdXIgcHJvamVjdCBhdCBgZm9yaW8uY29tL2FwcC95b3VyLWFjY291bnQtaWQveW91ci1wcm9qZWN0LWlkL2AuIFJlcXVpcmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcm9vdDogJy8nLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIG9wZXJhdGlvbnMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIGRvbWFpbjogJ2ZvcmlvLmNvbScsXG5cbiAgICAgICAgLy9PcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoa2V5LCByb290KSB7XG4gICAgICAgIGlmICghcm9vdCkge1xuICAgICAgICAgICAgcm9vdCA9IHNlcnZpY2VPcHRpb25zLnJvb3Q7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdkYXRhJykgKyBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKHJvb3QpO1xuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICB1cmwrPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBUaGUgbmFtZSBvZiB0aGUgZG9jdW1lbnQgdG8gc2VhcmNoLiBQYXNzIHRoZSBlbXB0eSBzdHJpbmcgKCcnKSB0byBzZWFyY2ggdGhlIGVudGlyZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHF1ZXJ5YCBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgdG8gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHtxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBrZXlgIElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWx1ZWAgKE9wdGlvbmFsKSBUaGUgZGF0YSB0byBzYXZlLiBJZiBga2V5YCBpcyBhIHN0cmluZywgdGhpcyBpcyB0aGUgdmFsdWUgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgdmFsdWUocykgdG8gc2F2ZSBhcmUgYWxyZWFkeSBwYXJ0IG9mIGBrZXlgIGFuZCB0aGlzIGFyZ3VtZW50IGlzIG5vdCByZXF1aXJlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhIG5hbWVkIGRvY3VtZW50IG9yIGVsZW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHNlcGFyYXRlbHkgaW4gY29uZmlndXJhdGlvbiBvcHRpb25zLCBlaXRoZXIgYXMgcGFydCBvZiB0aGUgY2FsbCBvciBhcyBwYXJ0IG9mIHRoZSBpbml0aWFsaXphdGlvbiBvZiBkcy5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYGtleWAgSWQgb2YgdGhlIGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYGtleWAgVGhlIGlkIG9mIHRoZSBkYXRhIHRvIHJldHVybi4gQ2FuIGJlIHRoZSBpZCBvZiBhIGRvY3VtZW50LCBvciBhIHBhdGggdG8gZGF0YSB3aXRoaW4gdGhhdCBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChrZXksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBkYXRhIGZyb20gY29sbGVjdGlvbi4gT25seSBkb2N1bWVudHMgKHRvcC1sZXZlbCBlbGVtZW50cyBpbiBlYWNoIGNvbGxlY3Rpb24pIGNhbiBiZSBkZWxldGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgZHMucmVtb3ZlKCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xBcnJheX0gYGtleXNgIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBwYXJhbXM7XG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KGtleXMpKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBpZDoga2V5cyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSAnJztcbiAgICAgICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5cywgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFcGljZW50ZXIgZG9lc24ndCBhbGxvdyBudWtpbmcgY29sbGVjdGlvbnNcbiAgICAgICAgLy8gICAgIC8qKlxuICAgICAgICAvLyAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgLy8gICAgICAqIEByZXR1cm4gbnVsbFxuICAgICAgICAvLyAgICAgICovXG4gICAgICAgIC8vICAgICBkZXN0cm95OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgnJywgb3B0aW9ucyk7XG4gICAgICAgIC8vICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyNNZW1iZXIgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgTWVtYmVyIEFQSSBBZGFwdGVyIHByb3ZpZGVzIG1ldGhvZHMgdG8gbG9vayB1cCBpbmZvcm1hdGlvbiBhYm91dCBlbmQgdXNlcnMgZm9yIHlvdXIgcHJvamVjdCBhbmQgaG93IHRoZXkgYXJlIGRpdmlkZWQgYWNyb3NzIGdyb3Vwcy4gSXQgaXMgYmFzZWQgb24gcXVlcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW01lbWJlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvbWVtYmVyLykuXG4gKlxuICogVGhpcyBpcyBvbmx5IG5lZWRlZCBmb3IgQXV0aGVudGljYXRlZCBwcm9qZWN0cywgdGhhdCBpcywgdGVhbSBwcm9qZWN0cyB3aXRoIFtlbmQgdXNlcnMgYW5kIGdyb3Vwc10oLi4vLi4vLi4vZ3JvdXBzX2FuZF9lbmRfdXNlcnMvKS4gRm9yIGV4YW1wbGUsIGlmIHNvbWUgb2YgeW91ciBlbmQgdXNlcnMgYXJlIGZhY2lsaXRhdG9ycywgb3IgaWYgeW91ciBlbmQgdXNlcnMgc2hvdWxkIGJlIHRyZWF0ZWQgZGlmZmVyZW50bHkgYmFzZWQgb24gd2hpY2ggZ3JvdXAgdGhleSBhcmUgaW4sIHVzZSB0aGUgTWVtYmVyIEFQSSB0byBmaW5kIHRoYXQgaW5mb3JtYXRpb24uXG4gKlxuICogICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gKiAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICdiNmIzMTNhMy1hYjg0LTQ3OWMtYmFlYS0yMDZmNmJmZjMzNycgfSk7XG4gKiAgICAgIG1hLmdldEdyb3VwRGV0YWlscyh7IGdyb3VwSWQ6ICcwMGI1MzMwOC05ODMzLTQ3ZjItYjIxZS0xMjc4YzA3ZDUzYjgnIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGFwaUVuZHBvaW50ID0gJ21lbWJlci9sb2NhbCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciB1c2VyIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBncm91cCBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuIE5vdGUgdGhhdCB0aGlzIGlzIHRoZSBncm91cCAqaWQqLCBub3QgdGhlIGdyb3VwICpuYW1lKi5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGdyb3VwSWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucywgc2VydmljZU9wdGlvbnMpO1xuXG4gICAgdmFyIGdldEZpbmFsUGFyYW1zID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBwYXRjaFVzZXJBY3RpdmVGaWVsZCA9IGZ1bmN0aW9uIChwYXJhbXMsIGFjdGl2ZSwgb3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBwYXJhbXMuZ3JvdXBJZCArICcvJyArIHBhcmFtcy51c2VySWRcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goeyBhY3RpdmU6IGFjdGl2ZSB9LCBodHRwT3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBhbGwgb2YgdGhlIGdyb3VwIG1lbWJlcnNoaXBzIGZvciBvbmUgZW5kIHVzZXIuIFRoZSBtZW1iZXJzaGlwIGRldGFpbHMgYXJlIHJldHVybmVkIGluIGFuIGFycmF5LCB3aXRoIG9uZSBlbGVtZW50IChncm91cCByZWNvcmQpIGZvciBlYWNoIGdyb3VwIHRvIHdoaWNoIHRoZSBlbmQgdXNlciBiZWxvbmdzLlxuICAgICAgICAqXG4gICAgICAgICogSW4gdGhlIG1lbWJlcnNoaXAgYXJyYXksIGVhY2ggZ3JvdXAgcmVjb3JkIGluY2x1ZGVzIHRoZSBncm91cCBpZCwgcHJvamVjdCBpZCwgYWNjb3VudCAodGVhbSkgaWQsIGFuZCBhbiBhcnJheSBvZiBtZW1iZXJzLiBIb3dldmVyLCBvbmx5IHRoZSB1c2VyIHdob3NlIHVzZXJJZCBpcyBpbmNsdWRlZCBpbiB0aGUgY2FsbCBpcyBsaXN0ZWQgaW4gdGhlIG1lbWJlcnMgYXJyYXkgKHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGVyZSBhcmUgb3RoZXIgbWVtYmVycyBpbiB0aGlzIGdyb3VwKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcignNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24obWVtYmVyc2hpcHMpe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPG1lbWJlcnNoaXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cobWVtYmVyc2hpcHNbaV0uZ3JvdXBJZCk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gYHBhcmFtc2AgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlci4gQWx0ZXJuYXRpdmVseSwgYW4gb2JqZWN0IHdpdGggZmllbGQgYHVzZXJJZGAgYW5kIHZhbHVlIHRoZSB1c2VyIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRHcm91cHNGb3JVc2VyOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB1c2VySWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ2V0UGFybXMgPSBpc1N0cmluZyA/IHsgdXNlcklkOiBwYXJhbXMgfSA6IF9waWNrKG9ialBhcmFtcywgJ3VzZXJJZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldFBhcm1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBvbmUgZ3JvdXAsIGluY2x1ZGluZyBhbiBhcnJheSBvZiBhbGwgaXRzIG1lbWJlcnMuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3VwRGV0YWlscygnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZ3JvdXApe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPGdyb3VwLm1lbWJlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhncm91cC5tZW1iZXJzW2ldLnVzZXJOYW1lKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIH1cbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoeyBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fSBgcGFyYW1zYCBUaGUgZ3JvdXAgaWQuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGBncm91cElkYCBhbmQgdmFsdWUgdGhlIGdyb3VwIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0R3JvdXBEZXRhaWxzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMuZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZ3JvdXBJZCBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBncm91cElkID0gaXNTdHJpbmcgPyBwYXJhbXMgOiBvYmpQYXJhbXMuZ3JvdXBJZDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIGdyb3VwSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgYWN0aXZlYC4gQWN0aXZlIGVuZCB1c2VycyBjYW4gYmUgYXNzaWduZWQgdG8gW3dvcmxkc10oLi4vd29ybGQtbWFuYWdlci8pIGluIG11bHRpcGxheWVyIGdhbWVzIGR1cmluZyBhdXRvbWF0aWMgYXNzaWdubWVudC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEubWFrZVVzZXJBY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIG1ha2VVc2VyQWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCB0cnVlLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBTZXQgYSBwYXJ0aWN1bGFyIGVuZCB1c2VyIGFzIGBpbmFjdGl2ZWAuIEluYWN0aXZlIGVuZCB1c2VycyBhcmUgbm90IGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VySW5hY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggdGhpcyBlbmQgdXNlciBiZWxvbmdzLCBhbmQgaW4gd2hpY2ggdGhlIGVuZCB1c2VyIHNob3VsZCBiZWNvbWUgaW5hY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckluYWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCBmYWxzZSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI1J1biBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBSdW4gQVBJIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBwZXJmb3JtIGNvbW1vbiB0YXNrcyBhcm91bmQgY3JlYXRpbmcgYW5kIHVwZGF0aW5nIHJ1bnMsIHZhcmlhYmxlcywgYW5kIGRhdGEuXG4gKlxuICogV2hlbiBidWlsZGluZyBpbnRlcmZhY2VzIHRvIHNob3cgcnVuIG9uZSBhdCBhIHRpbWUgKGFzIGZvciBzdGFuZGFyZCBlbmQgdXNlcnMpLCB0eXBpY2FsbHkgeW91IGZpcnN0IGluc3RhbnRpYXRlIGEgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGFuZCB0aGVuIGFjY2VzcyB0aGUgUnVuIFNlcnZpY2UgdGhhdCBpcyBhdXRvbWF0aWNhbGx5IHBhcnQgb2YgdGhlIG1hbmFnZXIsIHJhdGhlciB0aGFuIGluc3RhbnRpYXRpbmcgdGhlIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LiBUaGlzIGlzIGJlY2F1c2UgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLlxuICpcbiAqIEhvd2V2ZXIsIG1hbnkgb2YgdGhlIEVwaWNlbnRlciBzYW1wbGUgcHJvamVjdHMgdXNlIGEgUnVuIFNlcnZpY2UsIGJlY2F1c2UgZ2VuZXJhbGx5IHRoZSBzYW1wbGUgcHJvamVjdHMgYXJlIHBsYXllZCBpbiBvbmUgZW5kIHVzZXIgc2Vzc2lvbiBhbmQgZG9uJ3QgY2FyZSBhYm91dCBydW4gc3RhdGVzIG9yIFtydW4gc3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKS4gVGhlIFJ1biBBUEkgU2VydmljZSBpcyBhbHNvIHVzZWZ1bCBmb3IgYnVpbGRpbmcgYW4gaW50ZXJmYWNlIGZvciBhIGZhY2lsaXRhdG9yLCBiZWNhdXNlIGl0IG1ha2VzIGl0IGVhc3kgdG8gbGlzdCBkYXRhIGFjcm9zcyBtdWx0aXBsZSBydW5zICh1c2luZyB0aGUgYGZpbHRlcigpYCBhbmQgYHF1ZXJ5KClgIG1ldGhvZHMpLlxuICpcbiAqIFRvIHVzZSB0aGUgUnVuIEFQSSBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKlxuICogRm9yIGV4YW1wbGUsXG4gKlxuICogICAgICAgdmFyIHJzID0gbmV3IEYuc2VydmljZS5SdW4oe1xuICogICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgIH0pO1xuICogICAgICBycy5jcmVhdGUoJ3N1cHBseV9jaGFpbl9nYW1lLnB5JykudGhlbihmdW5jdGlvbihydW4pIHtcbiAqICAgICAgICAgICAgIHJzLmRvKCdzb21lT3BlcmF0aW9uJyk7XG4gKiAgICAgIH0pO1xuICpcbiAqXG4gKiBBZGRpdGlvbmFsbHksIGFsbCBBUEkgY2FsbHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFJ1biBBUEkgU2VydmljZSBkZWZhdWx0cyBsaXN0ZWQgYmVsb3cuXG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGBtb2RlbGAsIHRoZSBSdW4gU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKlxuICogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiAqICAgICAgICAgICBydW46IHtcbiAqICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseV9jaGFpbl9nYW1lLnB5JyxcbiAqICAgICAgICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICAgICAgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBybS5nZXRSdW4oKVxuICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBSdW4gU2VydmljZSxcbiAqICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4gKiAgICAgICAgICAgICAgIHZhciBycyA9IHJtLnJ1bjtcbiAqICAgICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgIH0pXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgVmFyaWFibGVzU2VydmljZSA9IHJlcXVpcmUoJy4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8IHN0b3JlLmdldCgnZXBpY2VudGVyLnRva2VuJykgfHwgJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgcnVucy4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlci5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRmxhZyBkZXRlcm1pbmVzIGlmIGBYLUF1dG9SZXN0b3JlOiB0cnVlYCBoZWFkZXIgaXMgc2VudCB0byBFcGljZW50ZXIuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBhdXRvUmVzdG9yZTogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuICAgIHVybENvbmZpZy5nZXRGaWx0ZXJVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJyk7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBxdXRpbC50b01hdHJpeEZvcm1hdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpO1xuXG4gICAgICAgIGlmIChmaWx0ZXIpIHtcbiAgICAgICAgICAgIHVybCArPSBmaWx0ZXIgKyAnLyc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmZpbHRlcjtcbiAgICAgICAgLy8gVGhlIHNlbWljb2xvbiBzZXBhcmF0ZWQgZmlsdGVyIGlzIHVzZWQgd2hlbiBmaWx0ZXIgaXMgYW4gb2JqZWN0XG4gICAgICAgIHZhciBpc0ZpbHRlclJ1bklkID0gZmlsdGVyICYmICQudHlwZShmaWx0ZXIpID09PSAnc3RyaW5nJztcbiAgICAgICAgaWYgKHNlcnZpY2VPcHRpb25zLmF1dG9SZXN0b3JlICYmIGlzRmlsdGVyUnVuSWQpIHtcbiAgICAgICAgICAgIC8vIEJ5IGRlZmF1bHQgYXV0b3JlcGxheSB0aGUgcnVuIGJ5IHNlbmRpbmcgdGhpcyBoZWFkZXIgdG8gZXBpY2VudGVyXG4gICAgICAgICAgICAvLyBodHRwczovL2ZvcmlvLmNvbS9lcGljZW50ZXIvZG9jcy9wdWJsaWMvcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNyZXRyaWV2aW5nXG4gICAgICAgICAgICB2YXIgYXV0b3Jlc3RvcmVPcHRzID0ge1xuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJ1gtQXV0b1Jlc3RvcmUnOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBhdXRvcmVzdG9yZU9wdHMsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgc2V0RmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBmaWx0ZXIgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgdXJsQ29uZmlnOiB1cmxDb25maWcsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyZWF0ZSBhIG5ldyBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIE5PVEU6IFR5cGljYWxseSB0aGlzIGlzIG5vdCB1c2VkISBVc2UgYFJ1bk1hbmFnZXIuZ2V0UnVuKClgIHdpdGggYSBgc3RyYXRlZ3lgIG9mIGBhbHdheXMtbmV3YCwgb3IgdXNlIGBSdW5NYW5hZ2VyLnJlc2V0KClgLiBTZWUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHJzLmNyZWF0ZSgnaGVsbG9fd29ybGQuamwnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYHBhcmFtc2AgSWYgYSBzdHJpbmcsIHRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IFttb2RlbCBmaWxlXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4gVGhpcyBpcyB0aGUgb25lIGZpbGUgaW4gdGhlIHByb2plY3QgdGhhdCBleHBsaWNpdGx5IGV4cG9zZXMgdmFyaWFibGVzIGFuZCBtZXRob2RzLCBhbmQgaXQgbXVzdCBiZSBzdG9yZWQgaW4gdGhlIE1vZGVsIGZvbGRlciBvZiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBJZiBhbiBvYmplY3QsIG1heSBpbmNsdWRlIGBtb2RlbGAsIGBzY29wZWAsIGFuZCBgZmlsZXNgLiAoU2VlIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bl9tYW5hZ2VyLykgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gYHNjb3BlYCBhbmQgYGZpbGVzYC4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICpcbiAgICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJykgfSk7XG4gICAgICAgICAgICB2YXIgcnVuQXBpUGFyYW1zID0gWydtb2RlbCcsICdzY29wZScsICdmaWxlcyddO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gdGhpcyBpcyBqdXN0IHRoZSBtb2RlbCBuYW1lXG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBtb2RlbDogcGFyYW1zIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHdoaXRlbGlzdCB0aGUgZmllbGRzIHRoYXQgd2UgYWN0dWFsbHkgY2FuIHNlbmQgdG8gdGhlIGFwaVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgcnVuQXBpUGFyYW1zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGVsZW1lbnRzIG9mIHRoZSBgcXNgIG9iamVjdCBhcmUgQU5EZWQgdG9nZXRoZXIgd2l0aGluIGEgc2luZ2xlIGNhbGwgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZXR1cm5zIHJ1bnMgd2l0aCBzYXZlZCA9IHRydWUgYW5kIHZhcmlhYmxlcy5wcmljZSA+IDEsXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgdmFyaWFibGVzLnByaWNlIGhhcyBiZWVuIHBlcnNpc3RlZCAocmVjb3JkZWQpXG4gICAgICAgICAqICAgICAgLy8gaW4gdGhlIG1vZGVsLlxuICAgICAgICAgKiAgICAgcnMucXVlcnkoe1xuICAgICAgICAgKiAgICAgICAgICAnc2F2ZWQnOiAndHJ1ZScsXG4gICAgICAgICAqICAgICAgICAgICcucHJpY2UnOiAnPjEnXG4gICAgICAgICAqICAgICAgIH0sXG4gICAgICAgICAqICAgICAgIHtcbiAgICAgICAgICogICAgICAgICAgc3RhcnRyZWNvcmQ6IDIsXG4gICAgICAgICAqICAgICAgICAgIGVuZHJlY29yZDogNVxuICAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBxc2AgUXVlcnkgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBRdWVyeWluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXMsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBxczsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFNpbWlsYXIgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJgIEZpbHRlciBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIEZpbHRlcmluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogZnVuY3Rpb24gKGZpbHRlciwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qoc2VydmljZU9wdGlvbnMuZmlsdGVyKSkge1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlcnZpY2VPcHRpb25zLmZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gZmlsdGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBkYXRhIGZvciBhIHNwZWNpZmljIHJ1bi4gVGhpcyBpbmNsdWRlcyBzdGFuZGFyZCBydW4gZGF0YSBzdWNoIGFzIHRoZSBhY2NvdW50LCBtb2RlbCwgcHJvamVjdCwgYW5kIGNyZWF0ZWQgYW5kIGxhc3QgbW9kaWZpZWQgZGF0ZXMuIFRvIHJlcXVlc3Qgc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLCBwYXNzIHRoZW0gYXMgcGFydCBvZiB0aGUgYGZpbHRlcnNgIHBhcmFtZXRlci5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IGlmIHRoZSBydW4gaXMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSksIGFueSBtb2RlbCB2YXJpYWJsZXMgYXJlIGF2YWlsYWJsZTsgaWYgdGhlIHJ1biBpcyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLCBvbmx5IG1vZGVsIHZhcmlhYmxlcyB0aGF0IGhhdmUgYmVlbiBwZXJzaXN0ZWQgJm1kYXNoOyB0aGF0IGlzLCBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwgJm1kYXNoOyBhcmUgYXZhaWxhYmxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgcnMubG9hZCgnYmI1ODk2NzctZDQ3Ni00OTcxLWE2OGUtMGM1OGQxOTFlNDUwJywgeyBpbmNsdWRlOiBbJy5wcmljZScsICcuc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBydW5JRGAgVGhlIHJ1biBpZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJzYCAoT3B0aW9uYWwpIE9iamVjdCBjb250YWluaW5nIGZpbHRlcnMgYW5kIG9wZXJhdGlvbiBtb2RpZmllcnMuIFVzZSBrZXkgYGluY2x1ZGVgIHRvIGxpc3QgbW9kZWwgdmFyaWFibGVzIHRoYXQgeW91IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUgcmVzcG9uc2UuIE90aGVyIGF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAocnVuSUQsIGZpbHRlcnMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmIChydW5JRCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJ1bklEOyAvL3Nob3VsZG4ndCBiZSBhYmxlIHRvIG92ZXItcmlkZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBhdHRyaWJ1dGVzIChkYXRhLCBtb2RlbCB2YXJpYWJsZXMpIG9mIHRoZSBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gYWRkICdjb21wbGV0ZWQnIGZpZWxkIHRvIHJ1biByZWNvcmRcbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBjb21wbGV0ZWQ6IHRydWUgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyB1cGRhdGUgJ3NhdmVkJyBmaWVsZCBvZiBydW4gcmVjb3JkLCBhbmQgdXBkYXRlIHZhbHVlcyBvZiBtb2RlbCB2YXJpYWJsZXMgZm9yIHRoaXMgcnVuXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgc2F2ZWQ6IHRydWUsIHZhcmlhYmxlczogeyBhOiAyMywgYjogMjMgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBhdHRyaWJ1dGVzYCBUaGUgcnVuIGRhdGEgYW5kIHZhcmlhYmxlcyB0byBzYXZlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGF0dHJpYnV0ZXMudmFyaWFibGVzYCBNb2RlbCB2YXJpYWJsZXMgbXVzdCBiZSBpbmNsdWRlZCBpbiBhIGB2YXJpYWJsZXNgIGZpZWxkIHdpdGhpbiB0aGUgYGF0dHJpYnV0ZXNgIG9iamVjdC4gKE90aGVyd2lzZSB0aGV5IGFyZSB0cmVhdGVkIGFzIHJ1biBkYXRhIGFuZCBhZGRlZCB0byB0aGUgcnVuIHJlY29yZCBkaXJlY3RseS4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uIChhdHRyaWJ1dGVzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKGF0dHJpYnV0ZXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBhIG1ldGhvZCBmcm9tIHRoZSBtb2RlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2QgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGBwYXJhbXNgIGFyZ3VtZW50IGlzIG5vcm1hbGx5IGFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byB0aGUgYG9wZXJhdGlvbmAuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXkuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCB5b3UgY2FuIGNvbWJpbmUgdGhlIGBvcGVyYXRpb25gIGFuZCBgcGFyYW1zYCBhcmd1bWVudHMgaW50byBhIHNpbmdsZSBvYmplY3QgaWYgeW91IHByZWZlciwgYXMgaW4gdGhlIGxhc3QgZXhhbXBsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic29sdmVcIiB0YWtlcyBubyBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLmRvKCdzb2x2ZScpO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsIFsnaGVsbG8nXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgJ2hlbGxvJyk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic3VtQXJyYXlcIiB0YWtlcyBvbmUgYXJndW1lbnQsIGFuIGFycmF5XG4gICAgICAgICAqICAgICBycy5kbygnc3VtQXJyYXknLCBbWzQsMiwxXV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImFkZFwiIHRha2VzIHR3byBhcmd1bWVudHMsIGJvdGggaW50ZWdlcnNcbiAgICAgICAgICogICAgIHJzLmRvKHsgbmFtZTonYWRkJywgcGFyYW1zOlsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYG9wZXJhdGlvbmAgTmFtZSBvZiBtZXRob2QuXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBwYXJhbXNgIChPcHRpb25hbCkgQW55IHBhcmFtZXRlcnMgdGhlIG9wZXJhdGlvbiB0YWtlcywgcGFzc2VkIGFzIGFuIGFycmF5LiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LCBhbmQgY2FuIGp1c3QgcGFzcyBpdCBkaXJlY3RseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZG86IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ2RvJywgb3BlcmF0aW9uLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wc0FyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnM7XG4gICAgICAgICAgICBpZiAob3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICAgICAgb3BzQXJncyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9uLCBvcHNBcmdzKTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgcG9zdE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcHJtcyA9IChyZXN1bHQuYXJnc1swXS5sZW5ndGggJiYgKHJlc3VsdC5hcmdzWzBdICE9PSBudWxsICYmIHJlc3VsdC5hcmdzWzBdICE9PSB1bmRlZmluZWQpKSA/IHJlc3VsdC5hcmdzWzBdIDogW107XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgYXJndW1lbnRzOiBwcm1zIH0sICQuZXh0ZW5kKHRydWUsIHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ29wZXJhdGlvbnMvJyArIHJlc3VsdC5vcHNbMF0gKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwsIHNlcXVlbnRpYWxseS5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2RzIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0aWFsaXplXCIgYW5kIFwic29sdmVcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWydpbml0aWFsaXplJywgJ3NvbHZlJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0XCIgYW5kIFwicmVzZXRcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncmVzZXQnLCBwYXJhbXM6IFsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJpbml0XCIgdGFrZXMgdHdvIGFyZ3VtZW50cyxcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJydW5tb2RlbFwiIHRha2VzIG5vbmVcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3J1bm1vZGVsJywgcGFyYW1zOiBbXSB9XSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBvcGVyYXRpb25zYCBJZiBub25lIG9mIHRoZSBtZXRob2RzIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgbWV0aG9kIG5hbWVzIChzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBtZXRob2RzIGRvIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGEgbWV0aG9kIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzZXJpYWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9TaW5nbGVPcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgb3AgPSBvcHMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICB2YXIgYXJnID0gYXJncy5zaGlmdCgpO1xuXG4gICAgICAgICAgICAgICAgbWUuZG8ob3AsIGFyZywge1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob3BzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbCwgZXhlY3V0aW5nIHRoZW0gaW4gcGFyYWxsZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kcyBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJzb2x2ZVwiIGFuZCBcInJlc2V0XCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWydzb2x2ZScsICdyZXNldCddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWyB7IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3N1YnRyYWN0JywgcGFyYW1zOlsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoeyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fSBgb3BlcmF0aW9uc2AgSWYgbm9uZSBvZiB0aGUgbWV0aG9kcyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG1ldGhvZCBuYW1lcyAoYXMgc3RyaW5ncykuIElmIGFueSBvZiB0aGUgbWV0aG9kcyBkbyB0YWtlIHBhcmFtZXRlcnMsIHlvdSBoYXZlIHR3byBvcHRpb25zLiBZb3UgY2FuIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhIG1ldGhvZCBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBwYXNzIGEgc2luZ2xlIG9iamVjdCB3aXRoIHRoZSBtZXRob2QgbmFtZSBhbmQgYSAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFsbGVsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG5cbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcXVldWUgID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaTwgb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcXVldWUucHVzaChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kbyhvcHNbaV0sIGFyZ3NbaV0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICQud2hlbi5hcHBseSh0aGlzLCBxdWV1ZSlcbiAgICAgICAgICAgICAgICAuZG9uZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2Vzcy5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvci5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY1N5bmNBUEkgPSB7XG4gICAgICAgIGdldEN1cnJlbnRDb25maWc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgfSxcbiAgICAgICAgLyoqXG4gICAgICAgICAgKiBSZXR1cm5zIGEgVmFyaWFibGVzIFNlcnZpY2UgaW5zdGFuY2UuIFVzZSB0aGUgdmFyaWFibGVzIGluc3RhbmNlIHRvIGxvYWQsIHNhdmUsIGFuZCBxdWVyeSBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLiBTZWUgdGhlIFtWYXJpYWJsZSBBUEkgU2VydmljZV0oLi4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAgICAgICAgKlxuICAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAgICAgIHZhciB2cyA9IHJzLnZhcmlhYmxlcygpO1xuICAgICAgICAgICogICAgICB2cy5zYXZlKHsgc2FtcGxlX2ludDogNCB9KTtcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBjb25maWdgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAgKi9cbiAgICAgICAgdmFyaWFibGVzOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgdnMgPSBuZXcgVmFyaWFibGVzU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZywge1xuICAgICAgICAgICAgICAgIHJ1blNlcnZpY2U6IHRoaXNcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIHJldHVybiB2cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljU3luY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4gKiAjI1N0YXRlIEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIFN0YXRlIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gcmVwbGF5IG9yIGNsb25lIHJ1bnMuIEl0IGJyaW5ncyBleGlzdGluZywgcGVyc2lzdGVkIHJ1biBkYXRhIGZyb20gdGhlIGRhdGFiYXNlIGJhY2sgaW50byBtZW1vcnksIHVzaW5nIHRoZSBzYW1lIHJ1biBpZCAoYHJlcGxheWApIG9yIGEgbmV3IHJ1biBpZCAoYGNsb25lYCkuIFJ1bnMgbXVzdCBiZSBpbiBtZW1vcnkgaW4gb3JkZXIgZm9yIHlvdSB0byB1cGRhdGUgdmFyaWFibGVzIG9yIGNhbGwgb3BlcmF0aW9ucyBvbiB0aGVtLlxuICpcbiAqIFNwZWNpZmljYWxseSwgdGhlIFN0YXRlIEFQSSBBZGFwdGVyIHdvcmtzIGJ5IFwicmUtcnVubmluZ1wiIHRoZSBydW4gKHVzZXIgaW50ZXJhY3Rpb25zKSBmcm9tIHRoZSBjcmVhdGlvbiBvZiB0aGUgcnVuIHVwIHRvIHRoZSB0aW1lIGl0IHdhcyBsYXN0IHBlcnNpc3RlZCBpbiB0aGUgZGF0YWJhc2UuIFRoaXMgcHJvY2VzcyB1c2VzIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIHJ1bidzIG1vZGVsLiBUaGVyZWZvcmUsIGlmIHRoZSBtb2RlbCBoYXMgY2hhbmdlZCBzaW5jZSB0aGUgb3JpZ2luYWwgcnVuIHdhcyBjcmVhdGVkLCB0aGUgcmV0cmlldmVkIHJ1biB3aWxsIHVzZSB0aGUgbmV3IG1vZGVsIOKAlCBhbmQgbWF5IGVuZCB1cCBoYXZpbmcgZGlmZmVyZW50IHZhbHVlcyBvciBiZWhhdmlvciBhcyBhIHJlc3VsdC4gVXNlIHdpdGggY2FyZSFcbiAqXG4gKiBUbyB1c2UgdGhlIFN0YXRlIEFQSSBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBjYWxsIGl0cyBtZXRob2RzOlxuICpcbiAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJ30pO1xuICpcbiAqIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgcHJvamVjdGAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4gKlxuICovXG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBhcGlFbmRwb2ludCA9ICdtb2RlbC9zdGF0ZSc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgfTtcblxuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcbiAgICB2YXIgcGFyc2VSdW5JZE9yRXJyb3IgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSAmJiBwYXJhbXMucnVuSWQpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbXMucnVuSWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwYXNzIGluIGEgcnVuIGlkJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGF5IGEgcnVuLiBBZnRlciB0aGlzIGNhbGwsIHRoZSBydW4sIHdpdGggaXRzIG9yaWdpbmFsIHJ1biBpZCwgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gKEl0IGNvbnRpbnVlcyB0byBiZSBwZXJzaXN0ZWQgaW50byB0aGUgRXBpY2VudGVyIGRhdGFiYXNlIGF0IHJlZ3VsYXIgaW50ZXJ2YWxzLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJywgc3RvcEJlZm9yZTogJ2NhbGN1bGF0ZVNjb3JlJ30pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBicmluZyBiYWNrIHRvIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBgcGFyYW1zLmV4Y2x1ZGVgIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZXBsYXk6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdyZXBsYXknIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ2xvbmUgYSBnaXZlbiBydW4gYW5kIHJldHVybiBhIG5ldyBydW4gaW4gdGhlIHNhbWUgc3RhdGUgYXMgdGhlIGdpdmVuIHJ1bi5cbiAgICAgICAgKlxuICAgICAgICAqIFRoZSBuZXcgcnVuIGlkIGlzIG5vdyBhdmFpbGFibGUgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIFRoZSBuZXcgcnVuIGluY2x1ZGVzIGEgY29weSBvZiBhbGwgb2YgdGhlIGRhdGEgZnJvbSB0aGUgb3JpZ2luYWwgcnVuLCBFWENFUFQ6XG4gICAgICAgICpcbiAgICAgICAgKiAqIFRoZSBgc2F2ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAuXG4gICAgICAgICogKiBUaGUgYGluaXRpYWxpemVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgbm90IGNvcGllZCBmcm9tIHRoZSBvcmlnaW5hbCBydW4gcmVjb3JkLiBJdCBkZWZhdWx0cyB0byBgZmFsc2VgIGJ1dCBtYXkgY2hhbmdlIHRvIGB0cnVlYCBhcyB0aGUgbmV3IHJ1biBpcyBhZHZhbmNlZC4gRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGhhcyBiZWVuIGEgY2FsbCB0byB0aGUgYHN0ZXBgIGZ1bmN0aW9uIChmb3IgVmVuc2ltIG1vZGVscyksIHRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGlzIHNldCB0byBgdHJ1ZWAuXG4gICAgICAgICogKiBUaGUgYGNyZWF0ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyB0aGUgZGF0ZSBhbmQgdGltZSBhdCB3aGljaCB0aGUgY2xvbmUgd2FzIGNyZWF0ZWQgKG5vdCB0aGUgdGltZSB0aGF0IHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQuKVxuICAgICAgICAqXG4gICAgICAgICogVGhlIG9yaWdpbmFsIHJ1biByZW1haW5zIG9ubHkgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLWRiKS5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5jbG9uZSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnLCBleGNsdWRlOiBbJ2ludGVyaW1DYWxjdWxhdGlvbiddIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBjbG9uZSBmcm9tIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBuZXdseSBjbG9uZWQgcnVuIGlzIGFkdmFuY2VkIG9ubHkgdXAgdG8gdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgdGhpcyBtZXRob2QuXG4gICAgICAgICogQHBhcmFtIHthcnJheX0gYHBhcmFtcy5leGNsdWRlYCAoT3B0aW9uYWwpIEFycmF5IG9mIG1ldGhvZHMgdG8gZXhjbHVkZSB3aGVuIGFkdmFuY2luZyB0aGUgbmV3bHkgY2xvbmVkIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGNsb25lOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcnVuSWQgPSBwYXJzZVJ1bklkT3JFcnJvcihwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgcmVwbGF5T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHJ1bklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgYWN0aW9uOiAnY2xvbmUnIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBlcGlWZXJzaW9uID0gcmVxdWlyZSgnLi4vYXBpLXZlcnNpb24uanNvbicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IHVybHV0aWxzIHRvIGdldCBob3N0LCBzaW5jZSBubyB3aW5kb3cgb24gbm9kZVxuXG4gICAgdmFyIEFQSV9QUk9UT0NPTCA9ICdodHRwcyc7XG4gICAgdmFyIEhPU1RfQVBJX01BUFBJTkcgPSB7XG4gICAgICAgICdmb3Jpby5jb20nOiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICdmb3Jpb2Rldi5jb20nOiAnYXBpLmVwaWNlbnRlci5mb3Jpb2Rldi5jb20nXG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNFeHBvcnRzID0ge1xuICAgICAgICBwcm90b2NvbDogQVBJX1BST1RPQ09MLFxuXG4gICAgICAgIGFwaTogJycsXG5cbiAgICAgICAgaG9zdDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICBpZiAoIWhvc3QgfHwgaG9zdC5pbmRleE9mKCdsb2NhbCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGhvc3QgPSAnZm9yaW8uY29tJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAoSE9TVF9BUElfTUFQUElOR1tob3N0XSkgPyBIT1NUX0FQSV9NQVBQSU5HW2hvc3RdIDogJ2FwaS4nICsgaG9zdDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBhcHBQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gcGF0aCAmJiBwYXRoWzFdIHx8ICcnO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFjY291bnRQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFjY250ID0gJyc7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIGFjY250ID0gcGF0aFsyXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhY2NudDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBwcm9qZWN0UGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwcmogPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIGlmIChwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnKSB7XG4gICAgICAgICAgICAgICAgcHJqID0gcGF0aFszXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBwcmo7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgdmVyc2lvblBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgdmVyc2lvbiA9IGVwaVZlcnNpb24udmVyc2lvbiA/IGVwaVZlcnNpb24udmVyc2lvbiArICcvJyA6ICcnO1xuICAgICAgICAgICAgcmV0dXJuIHZlcnNpb247XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgaXNMb2NhbGhvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICByZXR1cm4gKCFob3N0IHx8IGhvc3QuaW5kZXhPZignbG9jYWwnKSAhPT0gLTEpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGdldEFQSVBhdGg6IGZ1bmN0aW9uIChhcGkpIHtcbiAgICAgICAgICAgIHZhciBQUk9KRUNUX0FQSVMgPSBbJ3J1bicsICdkYXRhJywgJ2ZpbGUnXTtcblxuICAgICAgICAgICAgdmFyIGFwaVBhdGggPSB0aGlzLnByb3RvY29sICsgJzovLycgKyB0aGlzLmhvc3QgKyAnLycgKyB0aGlzLnZlcnNpb25QYXRoICsgYXBpICsgJy8nO1xuXG4gICAgICAgICAgICBpZiAoJC5pbkFycmF5KGFwaSwgUFJPSkVDVF9BUElTKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBhcGlQYXRoICs9IHRoaXMuYWNjb3VudFBhdGggKyAnLycgKyB0aGlzLnByb2plY3RQYXRoICArICcvJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhcGlQYXRoO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHB1YmxpY0V4cG9ydHMsIGNvbmZpZyk7XG4gICAgcmV0dXJuIHB1YmxpY0V4cG9ydHM7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4qICMjVXNlciBBUEkgQWRhcHRlclxuKlxuKiBUaGUgVXNlciBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHJldHJpZXZlIGRldGFpbHMgYWJvdXQgZW5kIHVzZXJzIGluIHlvdXIgdGVhbSAoYWNjb3VudCkuIEl0IGlzIGJhc2VkIG9uIHRoZSBxdWVyeWluZyBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbVXNlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvdXNlci8pLlxuKlxuKiBUbyB1c2UgdGhlIFVzZXIgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHMuXG4qXG4qICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nXG4qICAgICAgIH0pO1xuKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiogICAgICAgdWEuZ2V0KHsgdXNlck5hbWU6ICdqc21pdGgnIH0pO1xuKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4qXG4qIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgdG9rZW5gIGlmIHRoZXkgYXJlIG5vdCBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgY3VycmVudCBjb250ZXh0LlxuKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2Nlc3MgdG9rZW4gdG8gdXNlIHdoZW4gc2VhcmNoaW5nIGZvciBlbmQgdXNlcnMuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgcGFydGljdWxhciBlbmQgdXNlcnMgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIG5hbWUgb3IgdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4gICAgICAgICogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgZmlsdGVyYCBPYmplY3Qgd2l0aCBmaWVsZCBgdXNlck5hbWVgIGFuZCB2YWx1ZSBvZiB0aGUgdXNlcm5hbWUuIEFsdGVybmF0aXZlbHksIG9iamVjdCB3aXRoIGZpZWxkIGBpZGAgYW5kIHZhbHVlIG9mIGFuIGFycmF5IG9mIHVzZXIgaWRzLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWx0ZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciB0b1FGaWx0ZXIgPSBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgLy8gQVBJIG9ubHkgc3VwcG9ydHMgZmlsdGVyaW5nIGJ5IHVzZXJuYW1lIGZvciBub3dcbiAgICAgICAgICAgICAgICBpZiAoZmlsdGVyLnVzZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5xID0gZmlsdGVyLnVzZXJOYW1lO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgdG9JZEZpbHRlcnMgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZCA9ICQuaXNBcnJheShpZCkgPyBpZCA6IFtpZF07XG4gICAgICAgICAgICAgICAgcmV0dXJuICdpZD0nICsgaWQuam9pbignJmlkPScpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIGdldEZpbHRlcnMgPSBbXG4gICAgICAgICAgICAgICAgJ2FjY291bnQ9JyArIGdldE9wdGlvbnMuYWNjb3VudCxcbiAgICAgICAgICAgICAgICB0b0lkRmlsdGVycyhmaWx0ZXIuaWQpLFxuICAgICAgICAgICAgICAgIHF1dGlsLnRvUXVlcnlGb3JtYXQodG9RRmlsdGVyKGZpbHRlcikpXG4gICAgICAgICAgICBdLmpvaW4oJyYnKTtcblxuICAgICAgICAgICAgLy8gc3BlY2lhbCBjYXNlIGZvciBxdWVyaWVzIHdpdGggbGFyZ2UgbnVtYmVyIG9mIGlkc1xuICAgICAgICAgICAgLy8gbWFrZSBpdCBhcyBhIHBvc3Qgd2l0aCBHRVQgc2VtYW50aWNzXG4gICAgICAgICAgICB2YXIgdGhyZXNob2xkID0gMzA7XG4gICAgICAgICAgICBpZiAoZmlsdGVyLmlkICYmICQuaXNBcnJheShmaWx0ZXIuaWQpICYmIGZpbHRlci5pZC5sZW5ndGggPj0gdGhyZXNob2xkKSB7XG4gICAgICAgICAgICAgICAgZ2V0T3B0aW9ucy51cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpICsgJz9fbWV0aG9kPUdFVCc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGlkOiBmaWx0ZXIuaWQgfSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRGaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGEgc2luZ2xlIGVuZCB1c2VyIGluIHlvdXIgdGVhbSwgYmFzZWQgb24gdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRCeUlkOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcHVibGljQVBJLmdldCh7IGlkOiB1c2VySWQgfSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG5cblxuXG5cbiIsIi8qKlxuICpcbiAqICMjVmFyaWFibGVzIEFQSSBTZXJ2aWNlXG4gKlxuICogVXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSB0byByZWFkLCB3cml0ZSwgYW5kIHNlYXJjaCBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLlxuICpcbiAqICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJ1xuICogICAgICAgICAgIH1cbiAqICAgICAgfSk7XG4gKiAgICAgcm0uZ2V0UnVuKClcbiAqICAgICAgIC50aGVuKGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgdmFyIHZzID0gcm0ucnVuLnZhcmlhYmxlcygpO1xuICogICAgICAgICAgdnMuc2F2ZSh7c2FtcGxlX2ludDogNH0pO1xuICogICAgICAgIH0pO1xuICpcbiAqL1xuXG5cbiAndXNlIHN0cmljdCc7XG5cbiB2YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG4gdmFyIHJ1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9ydW4tdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcnVucyBvYmplY3QgdG8gd2hpY2ggdGhlIHZhcmlhYmxlIGZpbHRlcnMgYXBwbHkuIERlZmF1bHRzIHRvIG51bGwuXG4gICAgICAgICAqIEB0eXBlIHtydW5TZXJ2aWNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcnVuU2VydmljZTogbnVsbFxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ3ZhcmlhYmxlcy8nO1xuICAgIH07XG5cbiAgICB2YXIgYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9IHtcbiAgICAgICAgdXJsOiBnZXRVUkxcbiAgICB9O1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICBodHRwLnNwbGl0R2V0ID0gcnV0aWwuc3BsaXRHZXRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB2YWx1ZXMgZm9yIGEgdmFyaWFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMubG9hZCgnc2FtcGxlX2ludCcpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCl7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgY29udGFpbnMgdGhlIHZhbHVlIG9mIHNhbXBsZV9pbnRcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgdmFyaWFibGVgIE5hbWUgb2YgdmFyaWFibGUgdG8gbG9hZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHZhcmlhYmxlLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG91dHB1dE1vZGlmaWVyLCAkLmV4dGVuZCh7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IGdldFVSTCgpICsgdmFyaWFibGUgKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHZhcmlhYmxlcywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxdWVyeWAgb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KFsncHJpY2UnLCAnc2FsZXMnXSlcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgaXMgYW4gb2JqZWN0IHdpdGggdGhlIHZhbHVlcyBvZiB0aGUgcmVxdWVzdGVkIHZhcmlhYmxlczogdmFsLnByaWNlLCB2YWwuc2FsZXNcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoeyBpbmNsdWRlOlsncHJpY2UnLCAnc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IGBxdWVyeWAgVGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgcmVxdWVzdGVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9RdWVyeSBhbmQgb3V0cHV0TW9kaWZpZXIgYXJlIGJvdGggcXVlcnlzdHJpbmdzIGluIHRoZSB1cmw7IG9ubHkgY2FsbGluZyB0aGVtIG91dCBzZXBhcmF0ZWx5IGhlcmUgdG8gYmUgY29uc2lzdGVudCB3aXRoIHRoZSBvdGhlciBjYWxsc1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KHF1ZXJ5KSkge1xuICAgICAgICAgICAgICAgIHF1ZXJ5ID0geyBpbmNsdWRlOiBxdWVyeSB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJC5leHRlbmQocXVlcnksIG91dHB1dE1vZGlmaWVyKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KHF1ZXJ5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgdmFsdWVzIHRvIG1vZGVsIHZhcmlhYmxlcy4gT3ZlcndyaXRlcyBleGlzdGluZyB2YWx1ZXMuIE5vdGUgdGhhdCB5b3UgY2FuIG9ubHkgdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoQW4gYWx0ZXJuYXRlIHdheSB0byB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlzIHRvIGNhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwgYW5kIG1ha2Ugc3VyZSB0aGF0IHRoZSBtZXRob2QgcGVyc2lzdHMgdGhlIHZhcmlhYmxlcy4gU2VlIGBkb2AsIGBzZXJpYWxgLCBhbmQgYHBhcmFsbGVsYCBpbiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgZm9yIGNhbGxpbmcgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMuc2F2ZSgncHJpY2UnLCA0KTtcbiAgICAgICAgICogICAgICB2cy5zYXZlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgdmFyaWFibGVgIEFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgbW9kZWwgdmFyaWFibGVzIGFuZCB0aGUgdmFsdWVzIHRvIHNhdmUuIEFsdGVybmF0aXZlbHksIGEgc3RyaW5nIHdpdGggdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbGAgKE9wdGlvbmFsKSBJZiBwYXNzaW5nIGEgc3RyaW5nIGZvciBgdmFyaWFibGVgLCB1c2UgdGhpcyBhcmd1bWVudCBmb3IgdGhlIHZhbHVlIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uICh2YXJpYWJsZSwgdmFsLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW3ZhcmlhYmxlXSA9IHZhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoLmNhbGwodGhpcywgYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdCBBdmFpbGFibGUgdW50aWwgdW5kZXJseWluZyBBUEkgc3VwcG9ydHMgUFVULiBPdGhlcndpc2Ugc2F2ZSB3b3VsZCBiZSBQVVQgYW5kIG1lcmdlIHdvdWxkIGJlIFBBVENIXG4gICAgICAgIC8vICpcbiAgICAgICAgLy8gICogU2F2ZSB2YWx1ZXMgdG8gdGhlIGFwaS4gTWVyZ2VzIGFycmF5cywgYnV0IG90aGVyd2lzZSBzYW1lIGFzIHNhdmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSB2YXJpYWJsZSBPYmplY3Qgd2l0aCBhdHRyaWJ1dGVzLCBvciBzdHJpbmcga2V5XG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSB2YWwgT3B0aW9uYWwgaWYgcHJldiBwYXJhbWV0ZXIgd2FzIGEgc3RyaW5nLCBzZXQgdmFsdWUgaGVyZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAZXhhbXBsZVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSgncHJpY2UnLCA0KTtcblxuICAgICAgICAvLyBtZXJnZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgLy8gICAgIHZhciBhdHRycztcbiAgICAgICAgLy8gICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIC8vICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgIC8vICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAvLyAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAvLyAgICAgfVxuICAgICAgICAvLyAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAvLyAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICAvLyB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNXb3JsZCBBUEkgQWRhcHRlclxuICpcbiAqIEEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsIC0tIGluY2x1ZGluZyBzZXR0aW5nIHZhcmlhYmxlcywgbWFraW5nIGRlY2lzaW9ucywgYW5kIGNhbGxpbmcgb3BlcmF0aW9ucy4gRm9yIGJ1aWxkaW5nIG11bHRpcGxheWVyIHNpbXVsYXRpb25zIHlvdSB0eXBpY2FsbHkgd2FudCBtdWx0aXBsZSBlbmQgdXNlcnMgdG8gc2hhcmUgdGhlIHNhbWUgc2V0IG9mIGludGVyYWN0aW9ucywgYW5kIHdvcmsgd2l0aGluIGEgY29tbW9uIHN0YXRlLiBFcGljZW50ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUgXCJ3b3JsZHNcIiB0byBoYW5kbGUgc3VjaCBjYXNlcy4gT25seSBbdGVhbSBwcm9qZWN0c10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIGNhbiBiZSBtdWx0aXBsYXllci5cbiAqXG4gKiBUaGUgV29ybGQgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUsIGFjY2VzcywgYW5kIG1hbmlwdWxhdGUgbXVsdGlwbGF5ZXIgd29ybGRzIHdpdGhpbiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBZb3UgY2FuIHVzZSB0aGlzIHRvIGFkZCBhbmQgcmVtb3ZlIGVuZCB1c2VycyBmcm9tIHRoZSB3b3JsZCwgYW5kIHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgcmVtb3ZlIHRoZWlyIHJ1bnMuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4gKFRoZSByZWxhdGVkIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyLykgcHJvdmlkZXMgYW4gZWFzeSB3YXkgdG8gYWNjZXNzIHJ1bnMgYW5kIHdvcmxkcyBmb3IgcGFydGljdWxhciBlbmQgdXNlcnMsIHNvIGlzIHR5cGljYWxseSB1c2VkIGluIHBhZ2VzIHRoYXQgZW5kIHVzZXJzIHdpbGwgaW50ZXJhY3Qgd2l0aC4pXG4gKlxuICogQXMgd2l0aCBhbGwgdGhlIG90aGVyIFtBUEkgQWRhcHRlcnNdKC4uLy4uLyksIGFsbCBtZXRob2RzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBXb3JsZCBBUEkgU2VydmljZSBkZWZhdWx0cy5cbiAqXG4gKiBUbyB1c2UgdGhlIFdvcmxkIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSksIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKSwgYW5kIGdyb3VwICgqKkdyb3VwIE5hbWUqKikuXG4gKlxuICogICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gKiAgICAgICB3YS5jcmVhdGUoKVxuICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAqICAgICAgICAgICAgICAvLyBjYWxsIG1ldGhvZHMsIGUuZy4gd2EuYWRkVXNlcnMoKVxuICogICAgICAgICAgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG4vLyB2YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGFwaUJhc2UgPSAnbXVsdGlwbGF5ZXIvJztcbnZhciBhc3NpZ25tZW50RW5kcG9pbnQgPSBhcGlCYXNlICsgJ2Fzc2lnbic7XG52YXIgYXBpRW5kcG9pbnQgPSBhcGlCYXNlICsgJ3dvcmxkJztcbnZhciBwcm9qZWN0RW5kcG9pbnQgPSBhcGlCYXNlICsgJ3Byb2plY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkoeyBzeW5jaHJvbm91czogdHJ1ZSB9KTtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgZ3JvdXA6IHVuZGVmaW5lZCxcblxuICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIHJ1bnMgaW4gdGhpcyB3b3JsZC4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbW9kZWw6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JpdGVyaWEgYnkgd2hpY2ggdG8gZmlsdGVyIHdvcmxkLiBDdXJyZW50bHkgb25seSBzdXBwb3J0cyB3b3JsZC1pZHMgYXMgZmlsdGVycy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlbmllbmNlIGFsaWFzIGZvciBmaWx0ZXJcbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3BcbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMucHJvamVjdCA9IHVybENvbmZpZy5wcm9qZWN0UGF0aDtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBzZXRJZEZpbHRlck9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmlkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gd29ybGQgaWQgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdC4gVGhpcyBjb3VsZCBoYXBwZW4gaWYgdGhlIHVzZXIgaXMgbm90IGFzc2lnbmVkIHRvIGEgd29ybGQgYW5kIGlzIHRyeWluZyB0byB3b3JrIHdpdGggcnVucyBmcm9tIHRoYXQgd29ybGQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAoIW9wdGlvbnMubW9kZWwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gbW9kZWwgc3BlY2lmaWVkIHRvIGdldCB0aGUgY3VycmVudCBydW4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENyZWF0ZXMgYSBuZXcgV29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBVc2luZyB0aGlzIG1ldGhvZCBpcyByYXJlLiBJdCBpcyBtb3JlIGNvbW1vbiB0byBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkgd2hpbGUgeW91IGBhdXRvQXNzaWduKClgIGVuZCB1c2VycyB0byB3b3JsZHMuIChJbiB0aGlzIGNhc2UsIGNvbmZpZ3VyYXRpb24gZGF0YSBmb3IgdGhlIHdvcmxkLCBzdWNoIGFzIHRoZSByb2xlcywgYXJlIHJlYWQgZnJvbSB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9uLCBmb3IgZXhhbXBsZSBieSBgZ2V0UHJvamVjdFNldHRpbmdzKClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSh7XG4gICAgICAgICogICAgICAgICAgIHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddXG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBjcmVhdGUgdGhlIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwYCAoT3B0aW9uYWwpIFRoZSAqKkdyb3VwIE5hbWUqKiB0byBjcmVhdGUgdGhpcyB3b3JsZCB1bmRlci4gT25seSBlbmQgdXNlcnMgaW4gdGhpcyBncm91cCBhcmUgZWxpZ2libGUgdG8gam9pbiB0aGUgd29ybGQuIE9wdGlvbmFsIGhlcmU7IHJlcXVpcmVkIHdoZW4gaW5zdGFudGlhdGluZyB0aGUgc2VydmljZSAoYG5ldyBGLnNlcnZpY2UuV29ybGQoKWApLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfSk7XG4gICAgICAgICAgICB2YXIgd29ybGRBcGlQYXJhbXMgPSBbJ3Njb3BlJywgJ2ZpbGVzJywgJ3JvbGVzJywgJ29wdGlvbmFsUm9sZXMnLCAnbWluVXNlcnMnLCAnZ3JvdXAnLCAnbmFtZSddO1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHdvcmxkQXBpUGFyYW1zKTtcblxuICAgICAgICAgICAgLy8gYWNjb3VudCBhbmQgcHJvamVjdCBnbyBpbiB0aGUgYm9keSwgbm90IGluIHRoZSB1cmxcbiAgICAgICAgICAgICQuZXh0ZW5kKHBhcmFtcywgX3BpY2soc2VydmljZU9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pKTtcblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBVcGRhdGVzIGEgV29ybGQsIGZvciBleGFtcGxlIHRvIHJlcGxhY2UgdGhlIHJvbGVzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgeW91IGNvbXBsZXRlIHdvcmxkIGNvbmZpZ3VyYXRpb24gYXQgdGhlIHByb2plY3QgbGV2ZWwsIHJhdGhlciB0aGFuIGF0IHRoZSB3b3JsZCBsZXZlbC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguIEhvd2V2ZXIsIHRoaXMgbWV0aG9kIGlzIGF2YWlsYWJsZSBpZiB5b3UgbmVlZCB0byB1cGRhdGUgdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBwYXJ0aWN1bGFyIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnVwZGF0ZSh7IHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHVwZGF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMubmFtZWAgQSBzdHJpbmcgaWRlbnRpZmllciBmb3IgdGhlIGxpbmtlZCBlbmQgdXNlcnMsIGZvciBleGFtcGxlLCBcIm5hbWVcIjogXCJPdXIgVGVhbVwiLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHdoaXRlbGlzdCA9IFsncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycyddO1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHVwZGF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zIHx8IHt9LCB3aGl0ZWxpc3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChwYXJhbXMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYW4gZXhpc3Rpbmcgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBUaGlzIGZ1bmN0aW9uIG9wdGlvbmFsbHkgdGFrZXMgb25lIGFyZ3VtZW50LiBJZiB0aGUgYXJndW1lbnQgaXMgYSBzdHJpbmcsIGl0IGlzIHRoZSBpZCBvZiB0aGUgd29ybGQgdG8gZGVsZXRlLiBJZiB0aGUgYXJndW1lbnQgaXMgYW4gb2JqZWN0LCBpdCBpcyB0aGUgb3ZlcnJpZGUgZm9yIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmRlbGV0ZSgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUsIG9yIG9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAob3B0aW9ucyAmJiAodHlwZW9mIG9wdGlvbnMgPT09ICdzdHJpbmcnKSkgPyB7IGZpbHRlcjogb3B0aW9ucyB9IDoge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRlbGV0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGRlbGV0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBjdXJyZW50IGluc3RhbmNlIG9mIHRoZSBXb3JsZCBBUEkgQWRhcHRlciAoaW5jbHVkaW5nIGFsbCBzdWJzZXF1ZW50IGZ1bmN0aW9uIGNhbGxzLCB1bnRpbCB0aGUgY29uZmlndXJhdGlvbiBpcyB1cGRhdGVkIGFnYWluKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoey4uLn0pLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogJzEyMycgfSkuYWRkVXNlcih7IHVzZXJJZDogJzEyMycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgY29uZmlnYCBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gdXNlIGluIHVwZGF0aW5nIGV4aXN0aW5nIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZUNvbmZpZzogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMsIGNvbmZpZyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIExpc3RzIGFsbCB3b3JsZHMgZm9yIGEgZ2l2ZW4gYWNjb3VudCwgcHJvamVjdCwgYW5kIGdyb3VwLiBBbGwgdGhyZWUgYXJlIHJlcXVpcmVkLCBhbmQgaWYgbm90IHNwZWNpZmllZCBhcyBwYXJhbWV0ZXJzLCBhcmUgcmVhZCBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJ0ZWFtMVwiXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5saXN0KCk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJvdGhlci1ncm91cC1uYW1lXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoeyBncm91cDogJ290aGVyLWdyb3VwLW5hbWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBsaXN0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGFsbCB3b3JsZHMgdGhhdCBhbiBlbmQgdXNlciBiZWxvbmdzIHRvIGZvciBhIGdpdmVuIGFjY291bnQgKHRlYW0pLCBwcm9qZWN0LCBhbmQgZ3JvdXAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZ2V0V29ybGRzRm9yVXNlcignYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJylcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZHMgYXJlIGJlaW5nIHJldHJpZXZlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldFdvcmxkc0ZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YXIgZmlsdGVycyA9ICQuZXh0ZW5kKFxuICAgICAgICAgICAgICAgIF9waWNrKGdldE9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pLFxuICAgICAgICAgICAgICAgIHsgdXNlcklkOiB1c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGluZm9ybWF0aW9uIGZvciBhIHNwZWNpZmljIHdvcmxkLiBBbGwgZnVydGhlciBjYWxscyB0byB0aGUgd29ybGQgc2VydmljZSB3aWxsIHVzZSB0aGUgaWQgcHJvdmlkZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgd29ybGRJZGAgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBsb2FkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgd29ybGRpZCB0byBsb2FkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy8nIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQWRkcyBhbiBlbmQgdXNlciBvciBsaXN0IG9mIGVuZCB1c2VycyB0byBhIGdpdmVuIHdvcmxkLiBUaGUgZW5kIHVzZXIgbXVzdCBiZSBhIG1lbWJlciBvZiB0aGUgYGdyb3VwYCB0aGF0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlclxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoWydiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2Vycyh7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdWUCBTYWxlcycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBzZXZlcmFsIHVzZXJzXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgeyB1c2VySWQ6ICdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ1ZQIE1hcmtldGluZycgfSxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgRW5naW5lZXJpbmcnIH1cbiAgICAgICAgKiAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgICAgICAvLyBhZGQgb25lIHVzZXIgdG8gYSBzcGVjaWZpYyB3b3JsZFxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB7IGZpbHRlcjogd29ybGQuaWQgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdHxhcnJheX0gYHVzZXJzYCBVc2VyIGlkLCBhcnJheSBvZiB1c2VyIGlkcywgb2JqZWN0LCBvciBhcnJheSBvZiBvYmplY3RzIG9mIHRoZSB1c2VycyB0byBhZGQgdG8gdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJzLnJvbGVgIFRoZSBgcm9sZWAgdGhlIHVzZXIgc2hvdWxkIGhhdmUgaW4gdGhlIHdvcmxkLiBJdCBpcyB1cCB0byB0aGUgY2FsbGVyIHRvIGVuc3VyZSwgaWYgbmVlZGVkLCB0aGF0IHRoZSBgcm9sZWAgcGFzc2VkIGluIGlzIG9uZSBvZiB0aGUgYHJvbGVzYCBvciBgb3B0aW9uYWxSb2xlc2Agb2YgdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSB3b3JsZCB0byB3aGljaCB0aGUgdXNlcnMgc2hvdWxkIGJlIGFkZGVkLiBJZiBub3Qgc3BlY2lmaWVkLCB0aGUgZmlsdGVyIHBhcmFtZXRlciBvZiB0aGUgYG9wdGlvbnNgIG9iamVjdCBpcyB1c2VkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgYWRkVXNlcnM6IGZ1bmN0aW9uICh1c2Vycywgd29ybGRJZCwgb3B0aW9ucykge1xuXG4gICAgICAgICAgICBpZiAoIXVzZXJzKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhIGxpc3Qgb2YgdXNlcnMgdG8gYWRkIHRvIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBub3JtYWxpemUgdGhlIGxpc3Qgb2YgdXNlcnMgdG8gYW4gYXJyYXkgb2YgdXNlciBvYmplY3RzXG4gICAgICAgICAgICB1c2VycyA9ICQubWFwKFtdLmNvbmNhdCh1c2VycyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KHUpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1ICE9PSAnc3RyaW5nJyAmJiAhaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTb21lIG9mIHRoZSB1c2VycyBpbiB0aGUgbGlzdCBhcmUgbm90IGluIHRoZSB2YWxpZCBmb3JtYXQ6ICcgKyB1KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gaXNPYmplY3QgPyB1IDogeyB1c2VySWQ6IHUgfTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBjaGVjayBpZiBvcHRpb25zIHdlcmUgcGFzc2VkIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHdvcmxkSWQpICYmICFvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHdvcmxkSWQ7XG4gICAgICAgICAgICAgICAgd29ybGRJZCA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICAvLyB3ZSBtdXN0IGhhdmUgb3B0aW9ucyBieSBub3dcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygd29ybGRJZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvdXNlcnMnIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QodXNlcnMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIHJvbGUgb2YgYW4gZW5kIHVzZXIgaW4gYSBnaXZlbiB3b3JsZC4gKFlvdSBjYW4gb25seSB1cGRhdGUgb25lIGVuZCB1c2VyIGF0IGEgdGltZS4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuY3JlYXRlKCkudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgIHdhLnVwZGF0ZVVzZXIoeyB1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCByb2xlOiAnbGVhZGVyJyB9KTtcbiAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHVzZXJgIFVzZXIgb2JqZWN0IHdpdGggYHVzZXJJZGAgYW5kIHRoZSBuZXcgYHJvbGVgLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICghdXNlciB8fCAhdXNlci51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHBhc3MgYSB1c2VySWQgdG8gdXBkYXRlIGZyb20gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcGF0Y2hPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goX3BpY2sodXNlciwgJ3JvbGUnKSwgcGF0Y2hPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZW1vdmVzIGFuIGVuZCB1c2VyIGZyb20gYSBnaXZlbiB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5yZW1vdmVVc2VyKCdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoeyB1c2VySWQ6ICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdHxzdHJpbmd9IGB1c2VyYCBUaGUgYHVzZXJJZGAgb2YgdGhlIHVzZXIgdG8gcmVtb3ZlIGZyb20gdGhlIHdvcmxkLCBvciBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgYHVzZXJJZGAgZmllbGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdXNlciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICB1c2VyID0geyB1c2VySWQ6IHVzZXIgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHJ1biBpZCBvZiBjdXJyZW50IHJ1biBmb3IgdGhlIGdpdmVuIHdvcmxkLiBJZiB0aGUgd29ybGQgZG9lcyBub3QgaGF2ZSBhIHJ1biwgY3JlYXRlcyBhIG5ldyBvbmUgYW5kIHJldHVybnMgdGhlIHJ1biBpZC5cbiAgICAgICAgKlxuICAgICAgICAqIFJlbWVtYmVyIHRoYXQgYSBbcnVuXSguLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwuIEluIHRoZSBjYXNlIG9mIG11bHRpcGxheWVyIHByb2plY3RzLCB0aGUgcnVuIGlzIHNoYXJlZCBieSBhbGwgZW5kIHVzZXJzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRDdXJyZW50UnVuSWQoeyBtb2RlbDogJ21vZGVsLnB5JyB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRSdW5JZDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3J1bicgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoX3BpY2soZ2V0T3B0aW9ucywgJ21vZGVsJyksIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBmb3IgdGhlIGdpdmVuIGVuZCB1c2VyIGluIHRoZSBnaXZlbiBncm91cC4gQnJpbmdzIHRoaXMgbW9zdCByZWNlbnQgd29ybGQgaW50byBtZW1vcnkgaWYgbmVlZGVkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIHVzZSBkYXRhIGZyb20gd29ybGRcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSBjdXJyZW50IChtb3N0IHJlY2VudCkgd29ybGQgaXMgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cC4gSWYgbm90IHByb3ZpZGVkLCBkZWZhdWx0cyB0byB0aGUgZ3JvdXAgdXNlZCB0byBjcmVhdGUgdGhlIHNlcnZpY2UuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRXb3JsZEZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkc0ZvclVzZXIodXNlcklkLCB7IGdyb3VwOiBncm91cE5hbWUgfSlcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGFzc3VtZSB0aGUgbW9zdCByZWNlbnQgd29ybGQgYXMgdGhlICdhY3RpdmUnIHdvcmxkXG4gICAgICAgICAgICAgICAgICAgIHdvcmxkcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7IHJldHVybiBuZXcgRGF0ZShiLmxhc3RNb2RpZmllZCkgLSBuZXcgRGF0ZShhLmxhc3RNb2RpZmllZCk7IH0pO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VycmVudFdvcmxkID0gd29ybGRzWzBdO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50V29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9ICBjdXJyZW50V29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShjdXJyZW50V29ybGQsIG1lKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIHRoZSBjdXJyZW50IHJ1biBmcm9tIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIChOb3RlIHRoYXQgdGhlIHdvcmxkIGlkIHJlbWFpbnMgcGFydCBvZiB0aGUgcnVuIHJlY29yZCwgaW5kaWNhdGluZyB0aGF0IHRoZSBydW4gd2FzIGZvcm1lcmx5IGFuIGFjdGl2ZSBydW4gZm9yIHRoZSB3b3JsZC4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmRlbGV0ZVJ1bignc2FtcGxlLXdvcmxkLWlkJyk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSBgd29ybGRJZGAgb2YgdGhlIHdvcmxkIGZyb20gd2hpY2ggdGhlIGN1cnJlbnQgcnVuIGlzIGJlaW5nIGRlbGV0ZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGVSdW46IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBydW4gZm9yIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgd2EubmV3UnVuRm9yV29ybGQod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgd29ybGRJZCBpbiB3aGljaCB3ZSBjcmVhdGUgdGhlIG5ldyBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIG5ld1J1bkZvcldvcmxkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGN1cnJlbnRSdW5PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IGZpbHRlcjogd29ybGRJZCB8fCBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IoY3VycmVudFJ1bk9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kZWxldGVSdW4od29ybGRJZCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5nZXRDdXJyZW50UnVuSWQoY3VycmVudFJ1bk9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEFzc2lnbnMgZW5kIHVzZXJzIHRvIHdvcmxkcywgY3JlYXRpbmcgbmV3IHdvcmxkcyBhcyBhcHByb3ByaWF0ZSwgYXV0b21hdGljYWxseS4gQXNzaWducyBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cCwgYW5kIGNyZWF0ZXMgbmV3IHdvcmxkcyBhcyBuZWVkZWQgYmFzZWQgb24gdGhlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbiAocm9sZXMsIG9wdGlvbmFsIHJvbGVzLCBhbmQgbWluaW11bSBlbmQgdXNlcnMgcGVyIHdvcmxkKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5hdXRvQXNzaWduKCk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBhdXRvQXNzaWduOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhc3NpZ25tZW50RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBwYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3B0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgcHJvamVjdDogb3B0LnByb2plY3QsXG4gICAgICAgICAgICAgICAgZ3JvdXA6IG9wdC5ncm91cFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKG9wdC5tYXhVc2Vycykge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5tYXhVc2VycyA9IG9wdC5tYXhVc2VycztcbiAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgb3B0KTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBwcm9qZWN0J3Mgd29ybGQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgZXZlcnkgaW50ZXJhY3Rpb24gd2l0aCB5b3VyIHByb2plY3QgdXNlcyB0aGUgc2FtZSBjb25maWd1cmF0aW9uIG9mIGVhY2ggd29ybGQuIEZvciBleGFtcGxlLCBlYWNoIHdvcmxkIGluIHlvdXIgcHJvamVjdCBwcm9iYWJseSBoYXMgdGhlIHNhbWUgcm9sZXMgZm9yIGVuZCB1c2Vycy4gQW5kIHlvdXIgcHJvamVjdCBpcyBwcm9iYWJseSBlaXRoZXIgY29uZmlndXJlZCBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgc2hhcmUgdGhlIHNhbWUgd29ybGQgKGFuZCBydW4pLCBvciBzbWFsbGVyIHNldHMgb2YgZW5kIHVzZXJzIHNoYXJlIHdvcmxkcyDigJQgYnV0IG5vdCBib3RoLlxuICAgICAgICAqXG4gICAgICAgICogKFRoZSBbTXVsdGlwbGF5ZXIgUHJvamVjdCBSRVNUIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL211bHRpcGxheWVyX3Byb2plY3QvKSBhbGxvd3MgeW91IHRvIHNldCB0aGVzZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb25zLiBUaGUgV29ybGQgQWRhcHRlciBzaW1wbHkgcmV0cmlldmVzIHRoZW0sIGZvciBleGFtcGxlIHNvIHRoZXkgY2FuIGJlIHVzZWQgaW4gYXV0by1hc3NpZ25tZW50IG9mIGVuZCB1c2VycyB0byB3b3JsZHMuKVxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmdldFByb2plY3RTZXR0aW5ncygpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHNldHRpbmdzKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5yb2xlcyk7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5vcHRpb25hbFJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0UHJvamVjdFNldHRpbmdzOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChwcm9qZWN0RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIG9wdC51cmwgKz0gW29wdC5hY2NvdW50LCBvcHQucHJvamVjdF0uam9pbignLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQobnVsbCwgb3B0KTtcbiAgICAgICAgfVxuXG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29va2llIFN0b3JhZ2UgU2VydmljZVxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgIHZhciBwZW9wbGUgPSByZXF1aXJlKCdjb29raWUtc3RvcmUnKSh7IHJvb3Q6ICdwZW9wbGUnIH0pO1xuICAgICAgICBwZW9wbGVcbiAgICAgICAgICAgIC5zYXZlKHtsYXN0TmFtZTogJ3NtaXRoJyB9KVxuXG4gKi9cblxuXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5hbWUgb2YgY29sbGVjdGlvblxuICAgICAgICAgKiBAdHlwZSB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHJvb3Q6ICcvJyxcblxuICAgICAgICBkb21haW46ICcuZm9yaW8uY29tJ1xuICAgIH07XG4gICAgdGhpcy5zZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIC8vICogVEJEXG4gICAgICAgIC8vICAqIFF1ZXJ5IGNvbGxlY3Rpb247IHVzZXMgTW9uZ29EQiBzeW50YXhcbiAgICAgICAgLy8gICogQHNlZSAgPFRCRDogRGF0YSBBUEkgVVJMPlxuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IHFzIFF1ZXJ5IEZpbHRlclxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IGxpbWl0ZXJzIEBzZWUgPFRCRDogdXJsIGZvciBsaW1pdHMsIHBhZ2luZyBldGM+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBleGFtcGxlXG4gICAgICAgIC8vICAqICAgICBjcy5xdWVyeShcbiAgICAgICAgLy8gICogICAgICB7IG5hbWU6ICdKb2huJywgY2xhc3NOYW1lOiAnQ1NDMTAxJyB9LFxuICAgICAgICAvLyAgKiAgICAgIHtsaW1pdDogMTB9XG4gICAgICAgIC8vICAqICAgICApXG5cbiAgICAgICAgLy8gcXVlcnk6IGZ1bmN0aW9uIChxcywgbGltaXRlcnMpIHtcblxuICAgICAgICAvLyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGNvb2tpZSB2YWx1ZVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5ICAgSWYgZ2l2ZW4gYSBrZXkgc2F2ZSB2YWx1ZXMgdW5kZXIgaXQsIGlmIGdpdmVuIGFuIG9iamVjdCBkaXJlY3RseSwgc2F2ZSB0byB0b3AtbGV2ZWwgYXBpXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gdmFsdWUgKE9wdGlvbmFsKVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIHNlcnZpY2Ugb3B0aW9uc1xuICAgICAgICAgKlxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgc2F2ZWQgdmFsdWVcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnNldCgncGVyc29uJywgeyBmaXJzdE5hbWU6ICdqb2huJywgbGFzdE5hbWU6ICdzbWl0aCcgfSk7XG4gICAgICAgICAqICAgICBjcy5zZXQoeyBuYW1lOidzbWl0aCcsIGFnZTonMzInIH0pO1xuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHNldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5zZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSBzZXRPcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2V0T3B0aW9ucy5yb290O1xuXG4gICAgICAgICAgICBkb2N1bWVudC5jb29raWUgPSBlbmNvZGVVUklDb21wb25lbnQoa2V5KSArICc9JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuY29kZVVSSUNvbXBvbmVudCh2YWx1ZSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG5cbiAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9hZCBjb29raWUgdmFsdWVcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSAgIElmIGdpdmVuIGEga2V5IHNhdmUgdmFsdWVzIHVuZGVyIGl0LCBpZiBnaXZlbiBhbiBvYmplY3QgZGlyZWN0bHksIHNhdmUgdG8gdG9wLWxldmVsIGFwaVxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgdmFsdWUgc3RvcmVkXG4gICAgICAgICAqXG4gICAgICAgICAqIEBleGFtcGxlXG4gICAgICAgICAqICAgICBjcy5nZXQoJ3BlcnNvbicpO1xuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgY29va2llUmVnID0gbmV3IFJlZ0V4cCgnKD86KD86XnwuKjspXFxcXHMqJyArIGVuY29kZVVSSUNvbXBvbmVudChrZXkpLnJlcGxhY2UoL1tcXC1cXC5cXCtcXCpdL2csICdcXFxcJCYnKSArICdcXFxccypcXFxcPVxcXFxzKihbXjtdKikuKiQpfF4uKiQnKTtcbiAgICAgICAgICAgIHZhciB2YWwgPSBkb2N1bWVudC5jb29raWUucmVwbGFjZShjb29raWVSZWcsICckMScpO1xuICAgICAgICAgICAgdmFsID0gZGVjb2RlVVJJQ29tcG9uZW50KHZhbCkgfHwgbnVsbDtcbiAgICAgICAgICAgIHJldHVybiB2YWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMga2V5IGZyb20gY29sbGVjdGlvblxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGtleSBrZXkgdG8gcmVtb3ZlXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9IGtleSBUaGUga2V5IHJlbW92ZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnJlbW92ZSgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciByZW1PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMuc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9tYWluID0gcmVtT3B0aW9ucy5kb21haW47XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHJlbU9wdGlvbnMucm9vdDtcblxuICAgICAgICAgICAgZG9jdW1lbnQuY29va2llID0gZW5jb2RlVVJJQ29tcG9uZW50KGtleSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICc9OyBleHBpcmVzPVRodSwgMDEgSmFuIDE5NzAgMDA6MDA6MDAgR01UJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGRvbWFpbiA/ICc7IGRvbWFpbj0nICsgZG9tYWluIDogJycpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG4gICAgICAgICAgICByZXR1cm4ga2V5O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIGNvbGxlY3Rpb24gYmVpbmcgcmVmZXJlbmNlZFxuICAgICAgICAgKiBAcmV0dXJuIHsgYXJyYXl9IGtleXMgQWxsIHRoZSBrZXlzIHJlbW92ZWRcbiAgICAgICAgICovXG4gICAgICAgIGRlc3Ryb3k6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhS2V5cyA9IGRvY3VtZW50LmNvb2tpZS5yZXBsYWNlKC8oKD86XnxcXHMqOylbXlxcPV0rKSg/PTt8JCl8Xlxccyp8XFxzKig/OlxcPVteO10qKT8oPzpcXDF8JCkvZywgJycpLnNwbGl0KC9cXHMqKD86XFw9W147XSopPztcXHMqLyk7XG4gICAgICAgICAgICBmb3IgKHZhciBuSWR4ID0gMDsgbklkeCA8IGFLZXlzLmxlbmd0aDsgbklkeCsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvb2tpZUtleSA9IGRlY29kZVVSSUNvbXBvbmVudChhS2V5c1tuSWR4XSk7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmUoY29va2llS2V5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhS2V5cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICAgIERlY2lkZXMgdHlwZSBvZiBzdG9yZSB0byBwcm92aWRlXG4qL1xuXG4ndXNlIHN0cmljdCc7XG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHN0b3JlID0gKGlzTm9kZSkgPyByZXF1aXJlKCcuL3Nlc3Npb24tc3RvcmUnKSA6IHJlcXVpcmUoJy4vY29va2llLXN0b3JlJyk7XG52YXIgc3RvcmUgPSByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHN0b3JlO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgcXV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgIGhlYWRlcnM6IHt9LFxuICAgICAgICBzdGF0dXNDb2RlOiB7XG4gICAgICAgICAgICA0MDQ6ICQubm9vcFxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPTkxZIGZvciBzdHJpbmdzIGluIHRoZSB1cmwuIEFsbCBHRVQgJiBERUxFVEUgcGFyYW1zIGFyZSBydW4gdGhyb3VnaCB0aGlzXG4gICAgICAgICAqIEB0eXBlIHtbdHlwZV0gfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFyYW1ldGVyUGFyc2VyOiBxdXRpbHMudG9RdWVyeUZvcm1hdCxcblxuICAgICAgICAvLyBUbyBhbGxvdyBlcGljZW50ZXIudG9rZW4gYW5kIG90aGVyIHNlc3Npb24gY29va2llcyB0byBiZSBwYXNzZWRcbiAgICAgICAgLy8gd2l0aCB0aGUgcmVxdWVzdHNcbiAgICAgICAgeGhyRmllbGRzOiB7XG4gICAgICAgICAgICB3aXRoQ3JlZGVudGlhbHM6IHRydWVcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciByZXN1bHQgPSBmdW5jdGlvbiAoZCkge1xuICAgICAgICByZXR1cm4gKCQuaXNGdW5jdGlvbihkKSkgPyBkKCkgOiBkO1xuICAgIH07XG5cbiAgICB2YXIgY29ubmVjdCA9IGZ1bmN0aW9uIChtZXRob2QsIHBhcmFtcywgY29ubmVjdE9wdGlvbnMpIHtcbiAgICAgICAgcGFyYW1zID0gcmVzdWx0KHBhcmFtcyk7XG4gICAgICAgIHBhcmFtcyA9ICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSB8fCAkLmlzQXJyYXkocGFyYW1zKSkgPyBKU09OLnN0cmluZ2lmeShwYXJhbXMpIDogcGFyYW1zO1xuXG4gICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRyYW5zcG9ydE9wdGlvbnMsIGNvbm5lY3RPcHRpb25zLCB7XG4gICAgICAgICAgICB0eXBlOiBtZXRob2QsXG4gICAgICAgICAgICBkYXRhOiBwYXJhbXNcbiAgICAgICAgfSk7XG4gICAgICAgIHZhciBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUyA9IFsnZGF0YScsICd1cmwnXTtcbiAgICAgICAgJC5lYWNoKG9wdGlvbnMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAoJC5pc0Z1bmN0aW9uKHZhbHVlKSAmJiAkLmluQXJyYXkoa2V5LCBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9uc1trZXldID0gdmFsdWUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKG9wdGlvbnMubG9nTGV2ZWwgJiYgb3B0aW9ucy5sb2dMZXZlbCA9PT0gJ0RFQlVHJykge1xuICAgICAgICAgICAgY29uc29sZS5sb2cob3B0aW9ucy51cmwpO1xuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3NGbiA9IG9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UsIGFqYXhTdGF0dXMsIGFqYXhSZXEpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgb2xkU3VjY2Vzc0ZuLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGJlZm9yZVNlbmQgPSBvcHRpb25zLmJlZm9yZVNlbmQ7XG4gICAgICAgIG9wdGlvbnMuYmVmb3JlU2VuZCA9IGZ1bmN0aW9uICh4aHIsIHNldHRpbmdzKSB7XG4gICAgICAgICAgICB4aHIucmVxdWVzdFVybCA9IChjb25uZWN0T3B0aW9ucyB8fCB7fSkudXJsO1xuICAgICAgICAgICAgaWYgKGJlZm9yZVNlbmQpIHtcbiAgICAgICAgICAgICAgICBiZWZvcmVTZW5kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuICQuYWpheChvcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgZ2V0OmZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdHRVQnLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuICAgICAgICBzcGxpdEdldDogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIH0sXG4gICAgICAgIHBvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncG9zdCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgcGF0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncGF0Y2gnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHB1dDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwdXQnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKHBhcmFtcywgYWpheE9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vREVMRVRFIGRvZXNuJ3Qgc3VwcG9ydCBib2R5IHBhcmFtcywgYnV0IGpRdWVyeSB0aGlua3MgaXQgZG9lcy5cbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRyYW5zcG9ydE9wdGlvbnMsIGFqYXhPcHRpb25zKTtcbiAgICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1ldGVyUGFyc2VyKHJlc3VsdChwYXJhbXMpKTtcbiAgICAgICAgICAgIGlmICgkLnRyaW0ocGFyYW1zKSkge1xuICAgICAgICAgICAgICAgIHZhciBkZWxpbWl0ZXIgPSAocmVzdWx0KG9wdGlvbnMudXJsKS5pbmRleE9mKCc/JykgPT09IC0xKSA/ICc/JyA6ICcmJztcbiAgICAgICAgICAgICAgICBvcHRpb25zLnVybCA9IHJlc3VsdChvcHRpb25zLnVybCkgKyBkZWxpbWl0ZXIgKyBwYXJhbXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdERUxFVEUnLCBudWxsLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgaGVhZDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydoZWFkJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBvcHRpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ29wdGlvbnMnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHRyYW5zcG9ydCA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9ub2RlLWh0dHAtdHJhbnNwb3J0JykgOiByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbnZhciB0cmFuc3BvcnQgPSByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbm1vZHVsZS5leHBvcnRzID0gdHJhbnNwb3J0O1xuIiwiLyoqXG4vKiBJbmhlcml0IGZyb20gYSBjbGFzcyAodXNpbmcgcHJvdG90eXBlIGJvcnJvd2luZylcbiovXG4ndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIGluaGVyaXQoQywgUCkge1xuICAgIHZhciBGID0gZnVuY3Rpb24gKCkge307XG4gICAgRi5wcm90b3R5cGUgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZSA9IG5ldyBGKCk7XG4gICAgQy5fX3N1cGVyID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDO1xufVxuXG4vKipcbiogU2hhbGxvdyBjb3B5IG9mIGFuIG9iamVjdFxuKi9cbnZhciBleHRlbmQgPSBmdW5jdGlvbiAoZGVzdCAvKiwgdmFyX2FyZ3MqLykge1xuICAgIHZhciBvYmogPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHZhciBjdXJyZW50O1xuICAgIGZvciAodmFyIGogPSAwOyBqPG9iai5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAoIShjdXJyZW50ID0gb2JqW2pdKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkbyBub3Qgd3JhcCBpbm5lciBpbiBkZXN0Lmhhc093blByb3BlcnR5IG9yIGJhZCB0aGluZ3Mgd2lsbCBoYXBwZW5cbiAgICAgICAgLypqc2hpbnQgLVcwODkgKi9cbiAgICAgICAgZm9yICh2YXIga2V5IGluIGN1cnJlbnQpIHtcbiAgICAgICAgICAgIGRlc3Rba2V5XSA9IGN1cnJlbnRba2V5XTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkZXN0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYmFzZSwgcHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgdmFyIHBhcmVudCA9IGJhc2U7XG4gICAgdmFyIGNoaWxkO1xuXG4gICAgY2hpbGQgPSBwcm9wcyAmJiBwcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSA/IHByb3BzLmNvbnN0cnVjdG9yIDogZnVuY3Rpb24gKCkgeyByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IH07XG5cbiAgICAvLyBhZGQgc3RhdGljIHByb3BlcnRpZXMgdG8gdGhlIGNoaWxkIGNvbnN0cnVjdG9yIGZ1bmN0aW9uXG4gICAgZXh0ZW5kKGNoaWxkLCBwYXJlbnQsIHN0YXRpY1Byb3BzKTtcblxuICAgIC8vIGFzc29jaWF0ZSBwcm90b3R5cGUgY2hhaW5cbiAgICBpbmhlcml0KGNoaWxkLCBwYXJlbnQpO1xuXG4gICAgLy8gYWRkIGluc3RhbmNlIHByb3BlcnRpZXNcbiAgICBpZiAocHJvcHMpIHtcbiAgICAgICAgZXh0ZW5kKGNoaWxkLnByb3RvdHlwZSwgcHJvcHMpO1xuICAgIH1cblxuICAgIC8vIGRvbmVcbiAgICByZXR1cm4gY2hpbGQ7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLypqc2hpbnQgbG9vcGZ1bmM6ZmFsc2UgKi9cblxuZnVuY3Rpb24gX3codmFsKSB7XG4gICAgaWYgKHZhbCAmJiB2YWwudGhlbikge1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgIH1cbiAgICB2YXIgcCA9ICQuRGVmZXJyZWQoKTtcbiAgICBwLnJlc29sdmUodmFsKTtcblxuICAgIHJldHVybiBwLnByb21pc2UoKTtcbn1cblxuZnVuY3Rpb24gc2VxKCkge1xuICAgIHZhciBsaXN0ID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmFwcGx5KGFyZ3VtZW50cyk7XG5cbiAgICBmdW5jdGlvbiBuZXh0KHApIHtcbiAgICAgICAgdmFyIGN1ciA9IGxpc3Quc3BsaWNlKDAsMSlbMF07XG5cbiAgICAgICAgaWYgKCFjdXIpIHtcbiAgICAgICAgICAgIHJldHVybiBwO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF93KGN1cihwKSkudGhlbihuZXh0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gKHNlZWQpIHtcbiAgICAgICAgcmV0dXJuIG5leHQoc2VlZCkuZmFpbChzZXEuZmFpbCk7XG4gICAgfTtcbn1cblxuZnVuY3Rpb24gTWFrZVNlcShvYmopIHtcbiAgICB2YXIgcmVzID0ge1xuICAgICAgICBfX2NhbGxzOiBbXSxcblxuICAgICAgICBvcmlnaW5hbDogb2JqLFxuXG4gICAgICAgIHRoZW46IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goZm4pO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIC8vIGNsZWFuIHVwXG4gICAgICAgICAgICB0aGlzLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIF90aGlzLl9fY2FsbHMubGVuZ3RoID0gMDtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBzZXEuYXBwbHkobnVsbCwgdGhpcy5fX2NhbGxzKSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGZhaWw6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgc2VxLmZhaWwgPSBmbjtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBmdW5jTWFrZXIgPSBmdW5jdGlvbiAocCwgb2JqKSB7XG4gICAgICAgIHZhciBmbiA9IG9ialtwXS5iaW5kKG9iaik7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goRnVuY3Rpb24uYmluZC5hcHBseShmbiwgW251bGxdLmNvbmNhdChhcmdzKSkpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH07XG4gICAgfTtcblxuICAgIGZvciAodmFyIHByb3AgaW4gb2JqKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygb2JqW3Byb3BdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXNbcHJvcF0gPSBmdW5jTWFrZXIocHJvcCwgb2JqKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlc1twcm9wXSA9IG9ialtwcm9wXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gTWFrZVNlcTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgX3BpY2s6IGZ1bmN0aW9uIChvYmosIHByb3BzKSB7XG4gICAgICAgIHZhciByZXMgPSB7fTtcbiAgICAgICAgZm9yICh2YXIgcCBpbiBvYmopIHtcbiAgICAgICAgICAgIGlmIChwcm9wcy5pbmRleE9mKHApICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIHJlc1twXSA9IG9ialtwXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxufTtcbiIsIi8qKlxuICogVXRpbGl0aWVzIGZvciB3b3JraW5nIHdpdGggcXVlcnkgc3RyaW5nc1xuKi9cbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSAoZnVuY3Rpb24gKCkge1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHRvIG1hdHJpeCBmb3JtYXRcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBxcyBPYmplY3QgdG8gY29udmVydCB0byBxdWVyeSBzdHJpbmdcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ30gICAgTWF0cml4LWZvcm1hdCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuICAgICAgICB0b01hdHJpeEZvcm1hdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCB8fCBxcyA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJzsnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgdmFyIE9QRVJBVE9SUyA9IFsnPCcsICc+JywgJyEnXTtcbiAgICAgICAgICAgICQuZWFjaChxcywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnc3RyaW5nJyB8fCAkLmluQXJyYXkoJC50cmltKHZhbHVlKS5jaGFyQXQoMCksIE9QRVJBVE9SUykgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gJz0nICsgdmFsdWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciBtdHJ4ID0gJzsnICsgcmV0dXJuQXJyYXkuam9pbignOycpO1xuICAgICAgICAgICAgcmV0dXJuIG10cng7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHN0cmluZ3MvYXJyYXlzL29iamVjdHMgdG8gdHlwZSAnYT1iJmI9YydcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b1F1ZXJ5Rm9ybWF0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgJC5lYWNoKHFzLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmICgkLmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUuam9pbignLCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICAvL01vc3RseSBmb3IgZGF0YSBhcGlcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBKU09OLnN0cmluZ2lmeSh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgJz0nICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciByZXN1bHQgPSByZXR1cm5BcnJheS5qb2luKCcmJyk7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyBzdHJpbmdzIG9mIHR5cGUgJ2E9YiZiPWMnIHRvIHsgYTpiLCBiOmN9XG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHFzXG4gICAgICAgICAqIEByZXR1cm4ge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHFzVG9PYmplY3Q6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQgfHwgcXMgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcXNBcnJheSA9IHFzLnNwbGl0KCcmJyk7XG4gICAgICAgICAgICB2YXIgcmV0dXJuT2JqID0ge307XG4gICAgICAgICAgICAkLmVhY2gocXNBcnJheSwgZnVuY3Rpb24gKGluZGV4LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBxS2V5ID0gdmFsdWUuc3BsaXQoJz0nKVswXTtcbiAgICAgICAgICAgICAgICB2YXIgcVZhbCA9IHZhbHVlLnNwbGl0KCc9JylbMV07XG5cbiAgICAgICAgICAgICAgICBpZiAocVZhbC5pbmRleE9mKCcsJykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHFWYWwgPSBxVmFsLnNwbGl0KCcsJyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuT2JqW3FLZXldID0gcVZhbDtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuT2JqO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOb3JtYWxpemVzIGFuZCBtZXJnZXMgc3RyaW5ncyBvZiB0eXBlICdhPWInLCB7IGI6Y30gdG8geyBhOmIsIGI6Y31cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzMVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXMyXG4gICAgICAgICAqIEByZXR1cm4ge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIG1lcmdlUVM6IGZ1bmN0aW9uIChxczEsIHFzMikge1xuICAgICAgICAgICAgdmFyIG9iajEgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMSkpO1xuICAgICAgICAgICAgdmFyIG9iajIgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMikpO1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHt9LCBvYmoxLCBvYmoyKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhZGRUcmFpbGluZ1NsYXNoOiBmdW5jdGlvbiAodXJsKSB7XG4gICAgICAgICAgICBpZiAoIXVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAodXJsLmNoYXJBdCh1cmwubGVuZ3RoIC0gMSkgPT09ICcvJykgPyB1cmwgOiAodXJsICsgJy8nKTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuXG5cblxuIiwiLyoqXG4gKiBVdGlsaXRpZXMgZm9yIHdvcmtpbmcgd2l0aCB0aGUgcnVuIHNlcnZpY2VcbiovXG4ndXNlIHN0cmljdCc7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuL3F1ZXJ5LXV0aWwnKTtcbnZhciBNQVhfVVJMX0xFTkdUSCA9IDIwNDg7XG5cbm1vZHVsZS5leHBvcnRzID0gKGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICAvKipcbiAgICAgICAgICogcmV0dXJucyBvcGVyYXRpb25zIG9mIHRoZSBmb3JtIGBbW29wMSxvcDJdLCBbYXJnMSwgYXJnMl1dYFxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R8QXJyYXl8U3RyaW5nfSBgb3BlcmF0aW9uc2Agb3BlcmF0aW9ucyB0byBwZXJmb3JtXG4gICAgICAgICAqIEBwYXJhbSAge0FycmF5fSBgYXJnc2AgYXJndW1lbnRzIGZvciBvcGVyYXRpb25cbiAgICAgICAgICogQHJldHVybiB7U3RyaW5nfSAgICBNYXRyaXgtZm9ybWF0IHF1ZXJ5IHBhcmFtZXRlcnNcbiAgICAgICAgICovXG4gICAgICAgIG5vcm1hbGl6ZU9wZXJhdGlvbnM6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBhcmdzKSB7XG4gICAgICAgICAgICBpZiAoIWFyZ3MpIHtcbiAgICAgICAgICAgICAgICBhcmdzID0gW107XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgcmV0dXJuTGlzdCA9IHtcbiAgICAgICAgICAgICAgICBvcHM6IFtdLFxuICAgICAgICAgICAgICAgIGFyZ3M6IFtdXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX2NvbmNhdCA9IGZ1bmN0aW9uIChhcnIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKGFyciAhPT0gbnVsbCAmJiBhcnIgIT09IHVuZGVmaW5lZCkgPyBbXS5jb25jYXQoYXJyKSA6IFtdO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgLy97IGFkZDogWzEsMl0sIHN1YnRyYWN0OiBbMiw0XSB9XG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZVBsYWluT2JqZWN0cyA9IGZ1bmN0aW9uIChvcGVyYXRpb25zLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICQuZWFjaChvcGVyYXRpb25zLCBmdW5jdGlvbiAob3BuLCBhcmcpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcG4pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KGFyZykpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIC8veyBuYW1lOiAnYWRkJywgcGFyYW1zOiBbMV0gfVxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVTdHJ1Y3R1cmVkT2JqZWN0cyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcGVyYXRpb24ubmFtZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChvcGVyYXRpb24ucGFyYW1zKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZU9iamVjdCA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKChvcGVyYXRpb24ubmFtZSkgPyBfbm9ybWFsaXplU3RydWN0dXJlZE9iamVjdHMgOiBfbm9ybWFsaXplUGxhaW5PYmplY3RzKShvcGVyYXRpb24sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVMaXRlcmFscyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIGFyZ3MsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcGVyYXRpb24pO1xuICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQoYXJncykpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZUFycmF5cyA9IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBhcmcsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJC5lYWNoKG9wZXJhdGlvbnMsIGZ1bmN0aW9uIChpbmRleCwgb3BuKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qob3BuKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgX25vcm1hbGl6ZU9iamVjdChvcG4sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgX25vcm1hbGl6ZUxpdGVyYWxzKG9wbiwgYXJnc1tpbmRleF0sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KG9wZXJhdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZU9iamVjdChvcGVyYXRpb25zLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoJC5pc0FycmF5KG9wZXJhdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZUFycmF5cyhvcGVyYXRpb25zLCBhcmdzLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZUxpdGVyYWxzKG9wZXJhdGlvbnMsIGFyZ3MsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgfSxcblxuICAgICAgICBzcGxpdEdldEZhY3Rvcnk6IGZ1bmN0aW9uIChodHRwT3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICB2YXIgaHR0cCA9IHRoaXM7XG4gICAgICAgICAgICAgICAgdmFyIGdldFZhbHVlID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhbHVlID0gb3B0aW9uc1tuYW1lXSB8fCBodHRwT3B0aW9uc1tuYW1lXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciBnZXRGaW5hbFVybCA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybCA9IGdldFZhbHVlKCd1cmwnLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRhdGEgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZXJlIGlzIGVhc3kgKG9yIGtub3duKSB3YXkgdG8gZ2V0IHRoZSBmaW5hbCBVUkwganF1ZXJ5IGlzIGdvaW5nIHRvIHNlbmQgc29cbiAgICAgICAgICAgICAgICAgICAgLy8gd2UncmUgcmVwbGljYXRpbmcgaXQuIFRoZSBwcm9jZXNzIG1pZ2h0IGNoYW5nZSBhdCBzb21lIHBvaW50IGJ1dCBpdCBwcm9iYWJseSB3aWxsIG5vdC5cbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gUmVtb3ZlIGhhc2hcbiAgICAgICAgICAgICAgICAgICAgdXJsID0gdXJsLnJlcGxhY2UoLyMuKiQvLCAnJyk7XG4gICAgICAgICAgICAgICAgICAgIC8vIDEuIEFwcGVuZCBxdWVyeSBzdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXJ5UGFyYW1zID0gcXV0aWwudG9RdWVyeUZvcm1hdChkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXN0aW9uSWR4ID0gdXJsLmluZGV4T2YoJz8nKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHF1ZXJ5UGFyYW1zICYmIHF1ZXN0aW9uSWR4ID4gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmwgKyAnJicgKyBxdWVyeVBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChxdWVyeVBhcmFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybCArICc/JyArIHF1ZXJ5UGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmw7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgdXJsID0gZ2V0RmluYWxVcmwocGFyYW1zKTtcbiAgICAgICAgICAgICAgICAvLyBXZSBtdXN0IHNwbGl0IHRoZSBHRVQgaW4gbXVsdGlwbGUgc2hvcnQgVVJMJ3NcbiAgICAgICAgICAgICAgICAvLyBUaGUgb25seSBwcm9wZXJ0eSBhbGxvd2VkIHRvIGJlIHNwbGl0IGlzIFwiaW5jbHVkZVwiXG4gICAgICAgICAgICAgICAgaWYgKHBhcmFtcyAmJiBwYXJhbXMuaW5jbHVkZSAmJiB1cmwubGVuZ3RoID4gTUFYX1VSTF9MRU5HVEgpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmFtc0NvcHkgPSAkLmV4dGVuZCh0cnVlLCB7fSwgcGFyYW1zKTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHBhcmFtc0NvcHkuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybE5vSW5jbHVkZXMgPSBnZXRGaW5hbFVybChwYXJhbXNDb3B5KTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRpZmYgPSBNQVhfVVJMX0xFTkdUSCAtIHVybE5vSW5jbHVkZXMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IG9wdGlvbnMuc3VjY2VzcyB8fCBodHRwT3B0aW9ucy5zdWNjZXNzIHx8ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZEVycm9yID0gb3B0aW9ucy5lcnJvciB8fCBodHRwT3B0aW9ucy5lcnJvciB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSB0aGUgb3JpZ2luYWwgc3VjY2VzcyBhbmQgZXJyb3IgY2FsbGJhY2tzXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuc3VjY2VzcyA9ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvciA9ICQubm9vcDtcblxuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZSA9IHBhcmFtcy5pbmNsdWRlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VyckluY2x1ZGVzID0gW107XG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmNsdWRlT3B0cyA9IFtjdXJySW5jbHVkZXNdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHZhcmlhYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgYSBncmVlZHkgYXBwcm9hY2ggZm9yIG5vdywgY2FuIGJlIG9wdGltaXplZCB0byBiZSBzb2x2ZWQgaW4gYSBtb3JlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBlZmZpY2llbnQgd2F5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyArIDEgaXMgdGhlIGNvbW1hXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3Vyckxlbmd0aCArIHZhcmlhYmxlLmxlbmd0aCArIDEgPCBkaWZmKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzLnB1c2godmFyaWFibGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJMZW5ndGggKz0gdmFyaWFibGUubGVuZ3RoICsgMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzID0gW3ZhcmlhYmxlXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlT3B0cy5wdXNoKGN1cnJJbmNsdWRlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aCArIHZhcmlhYmxlLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB2YXIgcmVxcyA9ICQubWFwKGluY2x1ZGVPcHRzLCBmdW5jdGlvbiAoaW5jbHVkZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlcVBhcmFtcyA9ICQuZXh0ZW5kKHt9LCBwYXJhbXMsIHsgaW5jbHVkZTogaW5jbHVkZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChyZXFQYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgJC53aGVuLmFwcGx5KCQsIHJlcXMpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRWFjaCBhcmd1bWVudCBhcmUgYXJyYXlzIG9mIHRoZSBhcmd1bWVudHMgb2YgZWFjaCBkb25lIHJlcXVlc3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgZmlyc3QgYXJyYXkgb2YgYXJndW1lbnRzIGlzIHRoZSBkYXRhXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNWYWxpZCA9IGFyZ3VtZW50c1swXSAmJiBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaG91bGQgbmV2ZXIgaGFwcGVuLi4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpcnN0UmVzcG9uc2UgPSBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNSdW5BUEkgPSAoaXNPYmplY3QgJiYgJC5pc1BsYWluT2JqZWN0KGZpcnN0UmVzcG9uc2UudmFyaWFibGVzKSkgfHwgIWlzT2JqZWN0O1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzUnVuQVBJKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzT2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnZ3JlZ2F0ZSB0aGUgdmFyaWFibGVzIHByb3BlcnR5IG9ubHlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZVJ1biA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJ1biA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVSdW4udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZVJ1biwgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFycmF5IG9mIHJ1bnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWdyZWdhdGUgdmFyaWFibGVzIGluIGVhY2ggcnVuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkUnVucyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVucyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISQuaXNBcnJheShydW5zKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChydW5zLCBmdW5jdGlvbiAoaWR4UnVuLCBydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocnVuLmlkICYmICFhZ2dyZWdhdGVkUnVuc1tydW4uaWRdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bi52YXJpYWJsZXMgPSBydW4udmFyaWFibGVzIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVuc1tydW4uaWRdID0gcnVuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocnVuLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHR1cm4gaXQgaW50byBhbiBhcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVucyA9ICQubWFwKGFnZ3JlZ2F0ZWRSdW5zLCBmdW5jdGlvbiAocnVuKSB7IHJldHVybiBydW47IH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyB2YXJpYWJsZXMgQVBJXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSByZXNwb25zZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkVmFyaWFibGVzID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFycyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIHZhcnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IuYXBwbHkoaHR0cCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZWplY3QuYXBwbHkoZHRkLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuIl19 diff --git a/dist/epicenter.min.js b/dist/epicenter.min.js index 0f6aa7b7..b4488f28 100644 --- a/dist/epicenter.min.js +++ b/dist/epicenter.min.js @@ -17,7 +17,7 @@ var F={util:{},factory:{},transport:{},store:{},service:{},manager:{strategy:{}} }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./api-version.json":5,"./managers/auth-manager":7,"./managers/epicenter-channel-manager":9,"./managers/run-manager":11,"./managers/run-strategies/always-new-strategy":12,"./managers/run-strategies/conditional-creation-strategy":13,"./managers/run-strategies/identity-strategy":14,"./managers/run-strategies/new-if-initialized-strategy":16,"./managers/run-strategies/new-if-missing-strategy":17,"./managers/run-strategies/new-if-persisted-strategy":18,"./managers/scenario-manager":21,"./managers/world-manager":23,"./service/admin-file-service":24,"./service/asset-api-adapter":25,"./service/auth-api-service":26,"./service/channel-service":27,"./service/configuration-service":28,"./service/data-api-service":29,"./service/member-api-adapter":30,"./service/run-api-service":31,"./service/state-api-adapter":32,"./service/url-config-service":33,"./service/user-api-adapter":34,"./service/variables-api-service":35,"./service/world-api-adapter":36,"./store/cookie-store":37,"./store/store-factory":38,"./transport/ajax-http-transport":39,"./transport/http-transport-factory":40,"./util/inherit":41,"./util/make-sequence":42,"./util/query-util":44,"./util/run-util":45}],7:[function(require,module,exports){ -"use strict";function saveSession(userInfo,store){var serialized=JSON.stringify(userInfo);store.set(EPI_SESSION_KEY,serialized),store.set(EPI_COOKIE_KEY,userInfo.auth_token)}function getSession(store){var session=store.get(EPI_SESSION_KEY)||"{}";return JSON.parse(session)}function AuthManager(options){this.options=$.extend(!0,{},defaults,options);var urlConfig=new ConfigService(this.options).get("server");this.options.account||(this.options.account=urlConfig.accountPath),void 0===this.options.project&&(this.options.project=urlConfig.projectPath),void 0===this.options.store.root&&this.options.account&&this.options.project&&(this.options.store.root="/app/"+this.options.account+"/"+this.options.project),this.store=new StorageFactory(this.options.store),session=getSession(this.store),token=this.store.get(EPI_COOKIE_KEY)||"",this.authAdapter=new AuthAdapter(this.options,{token:session.auth_token})}var ConfigService=require("../service/configuration-service");var AuthAdapter=require("../service/auth-api-service");var MemberAdapter=require("../service/member-api-adapter");var StorageFactory=require("../store/store-factory");var Buffer=require("buffer").Buffer;var keyNames=require("./key-names");var defaults={store:{synchronous:!0}};var EPI_COOKIE_KEY=keyNames.EPI_COOKIE_KEY;var EPI_SESSION_KEY=keyNames.EPI_SESSION_KEY;var store;var token;var session;var _findUserInGroup=function(members,id){for(var j=0;j1&&groupId){var filteredGroups=$.grep(memberInfo,function(resGroup){return resGroup.groupId===groupId});group=1===filteredGroups.length?filteredGroups[0]:null}if(group){var groupSelection=group.groupId;data.groupSelection[adapterOptions.project]=groupSelection;var sessionInfoWithGroup=$.extend({},sessionInfo,{groupId:group.groupId,groupName:group.name,isFac:"facilitator"===_findUserInGroup(group.members,userInfo.user_id).role});saveSession(sessionInfoWithGroup,_this.store),outSuccess.apply(this,[data]),$d.resolve(data)}else handleGroupError("This user is associated with more than one group. Please specify a group id to log into and try again",403,data)}).fail($d.reject)};return adapterOptions.success=handleSuccess,adapterOptions.error=function(response){return adapterOptions.account?(adapterOptions.account=null,adapterOptions.error=function(){outError.apply(this,arguments),$d.reject(response)},void _this.authAdapter.login(adapterOptions)):(outError.apply(this,arguments),void $d.reject(response))},this.authAdapter.login(adapterOptions),$d.promise()},logout:function(options){var adapterOptions=$.extend(!0,{token:token},this.options,options);var removeCookieFn=function(response){store.remove(EPI_COOKIE_KEY,adapterOptions),store.remove(EPI_SESSION_KEY,adapterOptions),token=""};return this.authAdapter.logout(adapterOptions).done(removeCookieFn)},getToken:function(options){var httpOptions=$.extend(!0,this.options,options);var $d=$.Deferred();return token?$d.resolve(token):this.login(httpOptions).then($d.resolve),$d.promise()},getUserGroups:function(params,options){var adapterOptions=$.extend(!0,{success:$.noop},this.options,options);var $d=$.Deferred();var outSuccess=adapterOptions.success;adapterOptions.success=function(memberInfo){adapterOptions.project&&(memberInfo=$.grep(memberInfo,function(group){return group.project===adapterOptions.project})),outSuccess.apply(this,[memberInfo]),$d.resolve(memberInfo)};var memberAdapter=new MemberAdapter({token:params.token});return memberAdapter.getGroupsForUser(params,adapterOptions).fail($d.reject),$d.promise()},getCurrentUserSessionInfo:function(options){return getSession(this.store,options)}}),module.exports=AuthManager; +"use strict";function saveSession(userInfo,store){var serialized=JSON.stringify(userInfo);store.set(EPI_SESSION_KEY,serialized),store.set(EPI_COOKIE_KEY,userInfo.auth_token)}function getSession(store){var session=store.get(EPI_SESSION_KEY)||"{}";return JSON.parse(session)}function AuthManager(options){this.options=$.extend(!0,{},defaults,options);var urlConfig=new ConfigService(this.options).get("server");this.options.account||(this.options.account=urlConfig.accountPath),void 0===this.options.project&&(this.options.project=urlConfig.projectPath),this.store=new StorageFactory(this.options.store),session=getSession(this.store),token=this.store.get(EPI_COOKIE_KEY)||"",this.authAdapter=new AuthAdapter(this.options,{token:session.auth_token})}var ConfigService=require("../service/configuration-service");var AuthAdapter=require("../service/auth-api-service");var MemberAdapter=require("../service/member-api-adapter");var StorageFactory=require("../store/store-factory");var Buffer=require("buffer").Buffer;var keyNames=require("./key-names");var defaults={store:{synchronous:!0}};var EPI_COOKIE_KEY=keyNames.EPI_COOKIE_KEY;var EPI_SESSION_KEY=keyNames.EPI_SESSION_KEY;var store;var token;var session;var _findUserInGroup=function(members,id){for(var j=0;j1&&groupId){var filteredGroups=$.grep(memberInfo,function(resGroup){return resGroup.groupId===groupId});group=1===filteredGroups.length?filteredGroups[0]:null}if(group){var groupSelection=group.groupId;data.groupSelection[adapterOptions.project]=groupSelection;var sessionInfoWithGroup=$.extend({},sessionInfo,{groupId:group.groupId,groupName:group.name,isFac:"facilitator"===_findUserInGroup(group.members,userInfo.user_id).role});saveSession(sessionInfoWithGroup,_this.store),outSuccess.apply(this,[data]),$d.resolve(data)}else handleGroupError("This user is associated with more than one group. Please specify a group id to log into and try again",403,data)}).fail($d.reject)};return adapterOptions.success=handleSuccess,adapterOptions.error=function(response){return adapterOptions.account?(adapterOptions.account=null,adapterOptions.error=function(){outError.apply(this,arguments),$d.reject(response)},void _this.authAdapter.login(adapterOptions)):(outError.apply(this,arguments),void $d.reject(response))},this.authAdapter.login(adapterOptions),$d.promise()},logout:function(options){var adapterOptions=$.extend(!0,{token:token},this.options,options);var removeCookieFn=function(response){store.remove(EPI_COOKIE_KEY,adapterOptions),store.remove(EPI_SESSION_KEY,adapterOptions),token=""};return this.authAdapter.logout(adapterOptions).done(removeCookieFn)},getToken:function(options){var httpOptions=$.extend(!0,this.options,options);var $d=$.Deferred();return token?$d.resolve(token):this.login(httpOptions).then($d.resolve),$d.promise()},getUserGroups:function(params,options){var adapterOptions=$.extend(!0,{success:$.noop},this.options,options);var $d=$.Deferred();var outSuccess=adapterOptions.success;adapterOptions.success=function(memberInfo){adapterOptions.project&&(memberInfo=$.grep(memberInfo,function(group){return group.project===adapterOptions.project})),outSuccess.apply(this,[memberInfo]),$d.resolve(memberInfo)};var memberAdapter=new MemberAdapter({token:params.token});return memberAdapter.getGroupsForUser(params,adapterOptions).fail($d.reject),$d.promise()},getCurrentUserSessionInfo:function(options){return getSession(this.store,options)}}),module.exports=AuthManager; },{"../service/auth-api-service":26,"../service/configuration-service":28,"../service/member-api-adapter":30,"../store/store-factory":38,"./key-names":10,"buffer":1}],8:[function(require,module,exports){ "use strict";var Channel=require("../service/channel-service");var ChannelManager=function(options){if(!$.cometd)throw new Error("Cometd library not found. Please include epicenter-multiplayer-dependencies.js");if(!options||!options.url)throw new Error("Please provide an url for the cometd server");var defaults={url:"",logLevel:"info",websocketEnabled:!1,shareConnection:!1,channel:{}};var defaultCometOptions=$.extend(!0,{},defaults,options);if(this.currentSubscriptions=[],this.options=defaultCometOptions,defaultCometOptions.shareConnection&&ChannelManager.prototype._cometd)return this.cometd=ChannelManager.prototype._cometd,this;var cometd=new $.Cometd;ChannelManager.prototype._cometd=cometd,cometd.websocketEnabled=defaultCometOptions.websocketEnabled,this.isConnected=!1;var connectionBroken=function(message){$(this).trigger("disconnect",message)};var connectionSucceeded=function(message){$(this).trigger("connect",message)};var me=this;cometd.configure(defaultCometOptions),cometd.addListener("/meta/connect",function(message){var wasConnected=this.isConnected;this.isConnected=message.successful===!0,!wasConnected&&this.isConnected?connectionSucceeded.call(this,message):wasConnected&&!this.isConnected&&connectionBroken.call(this,message)}.bind(this)),cometd.addListener("/meta/disconnect",connectionBroken),cometd.addListener("/meta/handshake",function(message){message.successful&&cometd.batch(function(){$(me.currentSubscriptions).each(function(index,subs){cometd.resubscribe(subs)})})}),cometd.addListener("/meta/subscribe",function(message){$(me).trigger("subscribe",message)}),cometd.addListener("/meta/unsubscribe",function(message){$(me).trigger("unsubscribe",message)}),cometd.addListener("/meta/publish",function(message){$(me).trigger("publish",message)}),cometd.addListener("/meta/unsuccessful",function(message){$(me).trigger("error",message)}),cometd.handshake(),this.cometd=cometd};ChannelManager.prototype=$.extend(ChannelManager.prototype,{getChannel:function(options){options&&!$.isPlainObject(options)&&(options={base:options});var defaults={transport:this.cometd};var channel=new Channel($.extend(!0,{},this.options.channel,defaults,options));var subs=channel.subscribe;channel.subscribe=function(){var subid=subs.apply(channel,arguments);return this.currentSubscriptions=this.currentSubscriptions.concat(subid),subid}.bind(this);var unsubs=channel.unsubscribe;return channel.unsubscribe=function(){var removed=unsubs.apply(channel,arguments);for(var i=0;i\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && url.length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = '?include='.length;\n var variable = include.pop();\n while (variable) {\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + variable.length + 1 < diff) {\n currIncludes.push(variable);\n currLength += variable.length + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + variable.length;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ##File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n // config || (config = configService.get());\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || store.get('epicenter.token') || '',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: '',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {String} `folderType` One of Model|Static|Node\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, folderType, options) {\n var path = folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ##Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * ##Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: '',\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n domain: 'forio.com',\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ##Authentication API Service\n *\n * The Authentication API Service provides methods for logging in and logging out. On login, this service creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n * auth.logout();\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n /**\n * Logs user out from specified accounts.\n * Epicenter logout is not implemented yet, added a dummy promise that gets automatically resolved.\n *\n * **Example**\n *\n * auth.logout();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ##World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n $.extend(params, _pick(serviceOptions, ['account', 'project', 'group']));\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ##State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ##User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ##Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: '',\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar keyNames = require('../managers/key-names');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n var session = JSON.parse(store.get(keyNames.EPI_SESSION_KEY) || '{}');\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get(keyNames.EPI_COOKIE_KEY) || '',\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: session.userId,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n var serviceOptions = $.extend(true, {}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.forio.com'\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n\n document.cookie = encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookieReg = new RegExp('(?:(?:^|.*;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$');\n var val = document.cookie.replace(cookieReg, '$1');\n val = decodeURIComponent(val) || null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n\n document.cookie = encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var aKeys = document.cookie.replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* ####Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar ConfigService = require('../service/configuration-service');\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar StorageFactory = require('../store/store-factory');\nvar Buffer = require('buffer').Buffer;\nvar keyNames = require('./key-names');\n\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY;\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar store;\nvar token;\nvar session;\n\nfunction saveSession(userInfo, store) {\n var serialized = JSON.stringify(userInfo);\n store.set(EPI_SESSION_KEY, serialized);\n\n //jshint camelcase: false\n //jscs:disable\n store.set(EPI_COOKIE_KEY, userInfo.auth_token);\n}\n\nfunction getSession(store) {\n var session = store.get(EPI_SESSION_KEY) || '{}';\n return JSON.parse(session);\n}\n\nfunction AuthManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n var urlConfig = new ConfigService(this.options).get('server');\n if (!this.options.account) {\n this.options.account = urlConfig.accountPath;\n }\n\n // null might specified to disable project filtering\n if (this.options.project === undefined) {\n this.options.project = urlConfig.projectPath;\n }\n\n if (this.options.store.root === undefined && this.options.account && this.options.project) {\n this.options.store.root = '/app/' + this.options.account + '/' + this.options.project;\n }\n\n this.store = new StorageFactory(this.options.store);\n session = getSession(this.store);\n token = this.store.get(EPI_COOKIE_KEY) || '';\n //jshint camelcase: false\n //jscs:disable\n this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token });\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(memberInfo, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n var groupSelection = group.groupId;\n data.groupSelection[adapterOptions.project] = groupSelection;\n var sessionInfoWithGroup = $.extend({}, sessionInfo, {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n });\n saveSession(sessionInfoWithGroup, _this.store);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n }).fail($d.reject);\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var adapterOptions = $.extend(true, { token: token }, this.options, options);\n\n var removeCookieFn = function (response) {\n store.remove(EPI_COOKIE_KEY, adapterOptions);\n store.remove(EPI_SESSION_KEY, adapterOptions);\n token = '';\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = $.extend(true, this.options, options);\n\n var $d = $.Deferred();\n if (token) {\n $d.resolve(token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = $.extend(true, { success: $.noop }, this.options, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return getSession(this.store, options);\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `server` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `server.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `server.project` Epicenter project id.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\n\nvar AuthManager = require('./auth-manager');\n\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n var userInfo = session.getCurrentUserSessionInfo();\n\n var defaults = {\n account: userInfo.account,\n project: userInfo.project,\n };\n var defaultCometOptions = $.extend(true, {}, defaults, userInfo, options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getDataChannel('survey-responses');\n * gc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionStore = require('../../store/store-factory');\nvar classFrom = require('../../util/inherit');\nvar UrlService = require('../../service/url-config-service');\nvar AuthManager = require('../auth-manager');\n\nvar sessionStore = new SessionStore({});\nvar urlService = new UrlService();\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, path) {\n if (!path) {\n if (!urlService.isLocalhost()) {\n path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/');\n // make sure we don't get consecuteive '/' so we have a valid path for the session\n path = path.replace(/\\/{2,}/g,'/');\n } else {\n path = '';\n }\n }\n // set the seesionKey for the run\n sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path });\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.options.path);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession);\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","'use strict';\n\nmodule.exports = {\n EPI_COOKIE_KEY: 'epicenter.project.token',\n EPI_SESSION_KEY: 'epicenter.user.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","'use strict';\n\nvar Channel = require('../service/channel-service');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n }\n };\n var defaultCometOptions = $.extend(true, {}, defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake();\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('is-array')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\nBuffer.poolSize = 8192 // not used by this implementation\n\nvar rootParent = {}\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property\n * on objects.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\nfunction typedArraySupport () {\n function Bar () {}\n try {\n var arr = new Uint8Array(1)\n arr.foo = function () { return 42 }\n arr.constructor = Bar\n return arr.foo() === 42 && // typed array instances can be augmented\n arr.constructor === Bar && // constructor can be set\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\n/**\n * Class: Buffer\n * =============\n *\n * The Buffer constructor returns instances of `Uint8Array` that are augmented\n * with function properties for all the node `Buffer` API functions. We use\n * `Uint8Array` so that square bracket notation works as expected -- it returns\n * a single octet.\n *\n * By augmenting the instances, we can avoid modifying the `Uint8Array`\n * prototype.\n */\nfunction Buffer (arg) {\n if (!(this instanceof Buffer)) {\n // Avoid going through an ArgumentsAdaptorTrampoline in the common case.\n if (arguments.length > 1) return new Buffer(arg, arguments[1])\n return new Buffer(arg)\n }\n\n this.length = 0\n this.parent = undefined\n\n // Common case.\n if (typeof arg === 'number') {\n return fromNumber(this, arg)\n }\n\n // Slightly less common case.\n if (typeof arg === 'string') {\n return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')\n }\n\n // Unusual.\n return fromObject(this, arg)\n}\n\nfunction fromNumber (that, length) {\n that = allocate(that, length < 0 ? 0 : checked(length) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < length; i++) {\n that[i] = 0\n }\n }\n return that\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'\n\n // Assumption: byteLength() return value is always < kMaxLength.\n var length = byteLength(string, encoding) | 0\n that = allocate(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromObject (that, object) {\n if (Buffer.isBuffer(object)) return fromBuffer(that, object)\n\n if (isArray(object)) return fromArray(that, object)\n\n if (object == null) {\n throw new TypeError('must start with number, buffer, array or string')\n }\n\n if (typeof ArrayBuffer !== 'undefined') {\n if (object.buffer instanceof ArrayBuffer) {\n return fromTypedArray(that, object)\n }\n if (object instanceof ArrayBuffer) {\n return fromArrayBuffer(that, object)\n }\n }\n\n if (object.length) return fromArrayLike(that, object)\n\n return fromJsonObject(that, object)\n}\n\nfunction fromBuffer (that, buffer) {\n var length = checked(buffer.length) | 0\n that = allocate(that, length)\n buffer.copy(that, 0, 0, length)\n return that\n}\n\nfunction fromArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Duplicate of fromArray() to keep fromArray() monomorphic.\nfunction fromTypedArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n // Truncating the elements is probably not what people expect from typed\n // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior\n // of the old Buffer constructor.\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n array.byteLength\n that = Buffer._augment(new Uint8Array(array))\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromTypedArray(that, new Uint8Array(array))\n }\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.\n// Returns a zero-length buffer for inputs that don't conform to the spec.\nfunction fromJsonObject (that, object) {\n var array\n var length = 0\n\n if (object.type === 'Buffer' && isArray(object.data)) {\n array = object.data\n length = checked(array.length) | 0\n }\n that = allocate(that, length)\n\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n}\n\nfunction allocate (that, length) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = Buffer._augment(new Uint8Array(length))\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that.length = length\n that._isBuffer = true\n }\n\n var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1\n if (fromPool) that.parent = rootParent\n\n return that\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (subject, encoding) {\n if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)\n\n var buf = new Buffer(subject, encoding)\n delete buf.parent\n return buf\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n var i = 0\n var len = Math.min(x, y)\n while (i < len) {\n if (a[i] !== b[i]) break\n\n ++i\n }\n\n if (i !== len) {\n x = a[i]\n y = b[i]\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')\n\n if (list.length === 0) {\n return new Buffer(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; i++) {\n length += list[i].length\n }\n }\n\n var buf = new Buffer(length)\n var pos = 0\n for (i = 0; i < list.length; i++) {\n var item = list[i]\n item.copy(buf, pos)\n pos += item.length\n }\n return buf\n}\n\nfunction byteLength (string, encoding) {\n if (typeof string !== 'string') string = '' + string\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n // Deprecated\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\n// pre-set for values that may exist in the future\nBuffer.prototype.length = undefined\nBuffer.prototype.parent = undefined\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n start = start | 0\n end = end === undefined || end === Infinity ? this.length : end | 0\n\n if (!encoding) encoding = 'utf8'\n if (start < 0) start = 0\n if (end > this.length) end = this.length\n if (end <= start) return ''\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return 0\n return Buffer.compare(this, b)\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset) {\n if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff\n else if (byteOffset < -0x80000000) byteOffset = -0x80000000\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n if (val.length === 0) return -1 // special case: looking for empty string always fails\n return String.prototype.indexOf.call(this, val, byteOffset)\n }\n if (Buffer.isBuffer(val)) {\n return arrayIndexOf(this, val, byteOffset)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset)\n }\n\n function arrayIndexOf (arr, val, byteOffset) {\n var foundIndex = -1\n for (var i = 0; byteOffset + i < arr.length; i++) {\n if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex\n } else {\n foundIndex = -1\n }\n }\n return -1\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\n// `get` is deprecated\nBuffer.prototype.get = function get (offset) {\n console.log('.get() is deprecated. Access using array indexes instead.')\n return this.readUInt8(offset)\n}\n\n// `set` is deprecated\nBuffer.prototype.set = function set (v, offset) {\n console.log('.set() is deprecated. Access using array indexes instead.')\n return this.writeUInt8(v, offset)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; i++) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) throw new Error('Invalid hex string')\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n var swap = encoding\n encoding = offset\n offset = length | 0\n length = swap\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; i++) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = Buffer._augment(this.subarray(start, end))\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; i++) {\n newBuf[i] = this[i + start]\n }\n }\n\n if (newBuf.length) newBuf.parent = this.parent || this\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n if (offset < 0) throw new RangeError('index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; i--) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; i++) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n target._set(this.subarray(start, start + len), targetStart)\n }\n\n return len\n}\n\n// fill(value, start=0, end=buffer.length)\nBuffer.prototype.fill = function fill (value, start, end) {\n if (!value) value = 0\n if (!start) start = 0\n if (!end) end = this.length\n\n if (end < start) throw new RangeError('end < start')\n\n // Fill 0 bytes; we're done\n if (end === start) return\n if (this.length === 0) return\n\n if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')\n if (end < 0 || end > this.length) throw new RangeError('end out of bounds')\n\n var i\n if (typeof value === 'number') {\n for (i = start; i < end; i++) {\n this[i] = value\n }\n } else {\n var bytes = utf8ToBytes(value.toString())\n var len = bytes.length\n for (i = start; i < end; i++) {\n this[i] = bytes[i % len]\n }\n }\n\n return this\n}\n\n/**\n * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.\n * Added in Node 0.12. Only available in browsers that support ArrayBuffer.\n */\nBuffer.prototype.toArrayBuffer = function toArrayBuffer () {\n if (typeof Uint8Array !== 'undefined') {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n return (new Buffer(this)).buffer\n } else {\n var buf = new Uint8Array(this.length)\n for (var i = 0, len = buf.length; i < len; i += 1) {\n buf[i] = this[i]\n }\n return buf.buffer\n }\n } else {\n throw new TypeError('Buffer.toArrayBuffer not supported in this browser')\n }\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar BP = Buffer.prototype\n\n/**\n * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods\n */\nBuffer._augment = function _augment (arr) {\n arr.constructor = Buffer\n arr._isBuffer = true\n\n // save reference to original Uint8Array set method before overwriting\n arr._set = arr.set\n\n // deprecated\n arr.get = BP.get\n arr.set = BP.set\n\n arr.write = BP.write\n arr.toString = BP.toString\n arr.toLocaleString = BP.toString\n arr.toJSON = BP.toJSON\n arr.equals = BP.equals\n arr.compare = BP.compare\n arr.indexOf = BP.indexOf\n arr.copy = BP.copy\n arr.slice = BP.slice\n arr.readUIntLE = BP.readUIntLE\n arr.readUIntBE = BP.readUIntBE\n arr.readUInt8 = BP.readUInt8\n arr.readUInt16LE = BP.readUInt16LE\n arr.readUInt16BE = BP.readUInt16BE\n arr.readUInt32LE = BP.readUInt32LE\n arr.readUInt32BE = BP.readUInt32BE\n arr.readIntLE = BP.readIntLE\n arr.readIntBE = BP.readIntBE\n arr.readInt8 = BP.readInt8\n arr.readInt16LE = BP.readInt16LE\n arr.readInt16BE = BP.readInt16BE\n arr.readInt32LE = BP.readInt32LE\n arr.readInt32BE = BP.readInt32BE\n arr.readFloatLE = BP.readFloatLE\n arr.readFloatBE = BP.readFloatBE\n arr.readDoubleLE = BP.readDoubleLE\n arr.readDoubleBE = BP.readDoubleBE\n arr.writeUInt8 = BP.writeUInt8\n arr.writeUIntLE = BP.writeUIntLE\n arr.writeUIntBE = BP.writeUIntBE\n arr.writeUInt16LE = BP.writeUInt16LE\n arr.writeUInt16BE = BP.writeUInt16BE\n arr.writeUInt32LE = BP.writeUInt32LE\n arr.writeUInt32BE = BP.writeUInt32BE\n arr.writeIntLE = BP.writeIntLE\n arr.writeIntBE = BP.writeIntBE\n arr.writeInt8 = BP.writeInt8\n arr.writeInt16LE = BP.writeInt16LE\n arr.writeInt16BE = BP.writeInt16BE\n arr.writeInt32LE = BP.writeInt32LE\n arr.writeInt32BE = BP.writeInt32BE\n arr.writeFloatLE = BP.writeFloatLE\n arr.writeFloatBE = BP.writeFloatBE\n arr.writeDoubleLE = BP.writeDoubleLE\n arr.writeDoubleBE = BP.writeDoubleBE\n arr.fill = BP.fill\n arr.inspect = BP.inspect\n arr.toArrayBuffer = BP.toArrayBuffer\n\n return arr\n}\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; i++) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; i++) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n;(function (exports) {\n\t'use strict';\n\n var Arr = (typeof Uint8Array !== 'undefined')\n ? Uint8Array\n : Array\n\n\tvar PLUS = '+'.charCodeAt(0)\n\tvar SLASH = '/'.charCodeAt(0)\n\tvar NUMBER = '0'.charCodeAt(0)\n\tvar LOWER = 'a'.charCodeAt(0)\n\tvar UPPER = 'A'.charCodeAt(0)\n\tvar PLUS_URL_SAFE = '-'.charCodeAt(0)\n\tvar SLASH_URL_SAFE = '_'.charCodeAt(0)\n\n\tfunction decode (elt) {\n\t\tvar code = elt.charCodeAt(0)\n\t\tif (code === PLUS ||\n\t\t code === PLUS_URL_SAFE)\n\t\t\treturn 62 // '+'\n\t\tif (code === SLASH ||\n\t\t code === SLASH_URL_SAFE)\n\t\t\treturn 63 // '/'\n\t\tif (code < NUMBER)\n\t\t\treturn -1 //no match\n\t\tif (code < NUMBER + 10)\n\t\t\treturn code - NUMBER + 26 + 26\n\t\tif (code < UPPER + 26)\n\t\t\treturn code - UPPER\n\t\tif (code < LOWER + 26)\n\t\t\treturn code - LOWER + 26\n\t}\n\n\tfunction b64ToByteArray (b64) {\n\t\tvar i, j, l, tmp, placeHolders, arr\n\n\t\tif (b64.length % 4 > 0) {\n\t\t\tthrow new Error('Invalid string. Length must be a multiple of 4')\n\t\t}\n\n\t\t// the number of equal signs (place holders)\n\t\t// if there are two placeholders, than the two characters before it\n\t\t// represent one byte\n\t\t// if there is only one, then the three characters before it represent 2 bytes\n\t\t// this is just a cheap hack to not do indexOf twice\n\t\tvar len = b64.length\n\t\tplaceHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0\n\n\t\t// base64 is 4/3 + up to two characters of the original data\n\t\tarr = new Arr(b64.length * 3 / 4 - placeHolders)\n\n\t\t// if there are placeholders, only get up to the last complete 4 chars\n\t\tl = placeHolders > 0 ? b64.length - 4 : b64.length\n\n\t\tvar L = 0\n\n\t\tfunction push (v) {\n\t\t\tarr[L++] = v\n\t\t}\n\n\t\tfor (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))\n\t\t\tpush((tmp & 0xFF0000) >> 16)\n\t\t\tpush((tmp & 0xFF00) >> 8)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\tif (placeHolders === 2) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)\n\t\t\tpush(tmp & 0xFF)\n\t\t} else if (placeHolders === 1) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)\n\t\t\tpush((tmp >> 8) & 0xFF)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\treturn arr\n\t}\n\n\tfunction uint8ToBase64 (uint8) {\n\t\tvar i,\n\t\t\textraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes\n\t\t\toutput = \"\",\n\t\t\ttemp, length\n\n\t\tfunction encode (num) {\n\t\t\treturn lookup.charAt(num)\n\t\t}\n\n\t\tfunction tripletToBase64 (num) {\n\t\t\treturn encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)\n\t\t}\n\n\t\t// go through the array every three bytes, we'll deal with trailing stuff later\n\t\tfor (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n\t\t\ttemp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n\t\t\toutput += tripletToBase64(temp)\n\t\t}\n\n\t\t// pad the end with zeros, but make sure to not forget the extra bytes\n\t\tswitch (extraBytes) {\n\t\t\tcase 1:\n\t\t\t\ttemp = uint8[uint8.length - 1]\n\t\t\t\toutput += encode(temp >> 2)\n\t\t\t\toutput += encode((temp << 4) & 0x3F)\n\t\t\t\toutput += '=='\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\ttemp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])\n\t\t\t\toutput += encode(temp >> 10)\n\t\t\t\toutput += encode((temp >> 4) & 0x3F)\n\t\t\t\toutput += encode((temp << 2) & 0x3F)\n\t\t\t\toutput += '='\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn output\n\t}\n\n\texports.toByteArray = b64ToByteArray\n\texports.fromByteArray = uint8ToBase64\n}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))\n","\n/**\n * isArray\n */\n\nvar isArray = Array.isArray;\n\n/**\n * toString\n */\n\nvar str = Object.prototype.toString;\n\n/**\n * Whether or not the given `val`\n * is an array.\n *\n * example:\n *\n * isArray([]);\n * // > true\n * isArray(arguments);\n * // > false\n * isArray('');\n * // > false\n *\n * @param {mixed} val\n * @return {bool}\n */\n\nmodule.exports = isArray || function (val) {\n return !! val && '[object Array]' == str.call(val);\n};\n"]} \ No newline at end of file +{"version":3,"sources":["node_modules/grunt-browserify/node_modules/browserify/node_modules/browser-pack/_prelude.js","src/api-version.json","src/app.js","src/util/query-util.js","src/util/make-sequence.js","src/util/run-util.js","src/util/inherit.js","src/transport/http-transport-factory.js","src/transport/ajax-http-transport.js","src/service/url-config-service.js","src/service/configuration-service.js","src/service/run-api-service.js","src/service/admin-file-service.js","src/service/variables-api-service.js","src/service/data-api-service.js","src/service/auth-api-service.js","src/service/world-api-adapter.js","src/service/state-api-adapter.js","src/service/user-api-adapter.js","src/service/member-api-adapter.js","src/service/asset-api-adapter.js","src/store/cookie-store.js","src/store/store-factory.js","src/managers/scenario-manager.js","src/managers/run-manager.js","src/managers/auth-manager.js","src/managers/world-manager.js","src/managers/epicenter-channel-manager.js","src/service/channel-service.js","src/managers/run-strategies/always-new-strategy.js","src/managers/run-strategies/conditional-creation-strategy.js","src/managers/run-strategies/identity-strategy.js","src/managers/run-strategies/new-if-missing-strategy.js","src/managers/run-strategies/new-if-persisted-strategy.js","src/managers/run-strategies/new-if-initialized-strategy.js","src/util/object-util.js","src/managers/key-names.js","src/managers/special-operations.js","src/managers/channel-manager.js","src/managers/run-strategies/strategies-map.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/index.js","src/managers/run-strategies/multiplayer-strategy.js","src/managers/run-strategies/persistent-single-player-strategy.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/ieee754/index.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/base64-js/lib/b64.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/is-array/index.js"],"names":["F","util","factory","transport","store","service","manager","strategy","query","require","makeSequence","run","classFrom","Transport","Ajax","URL","Config","Run","File","Variables","Data","Auth","World","State","User","Member","Asset","Cookie","Store","ScenarioManager","RunManager","AuthManager","WorldManager","identity","ChannelManager","Channel","version","api","global","module","exports","toMatrixFormat","qs","undefined","String","returnArray","OPERATORS","$","each","key","value","inArray","trim","charAt","push","mtrx","join","toQueryFormat","isArray","isPlainObject","JSON","stringify","result","qsToObject","qsArray","split","returnObj","index","qKey","qVal","indexOf","mergeQS","qs1","qs2","obj1","this","obj2","extend","addTrailingSlash","url","length","_w","val","then","p","Deferred","resolve","promise","seq","next","cur","list","splice","Array","prototype","slice","apply","arguments","seed","fail","MakeSeq","obj","res","__calls","original","fn","start","_this","funcMaker","bind","args","Function","concat","prop","qutil","MAX_URL_LENGTH","normalizeOperations","operations","returnList","ops","_concat","arr","_normalizePlainObjects","opn","arg","_normalizeStructuredObjects","operation","name","params","_normalizeObject","_normalizeLiterals","_normalizeArrays","splitGetFactory","httpOptions","options","http","getValue","getFinalUrl","data","replace","queryParams","questionIdx","include","dtd","paramsCopy","urlNoIncludes","diff","oldSuccess","success","noop","oldError","error","currIncludes","includeOpts","currLength","variable","pop","reqs","map","reqParams","get","when","isValid","reject","firstResponse","isObject","isRunAPI","variables","aggregateRun","idx","aggregatedRuns","runs","idxRun","id","aggregatedVariables","vars","inherit","C","P","__super","constructor","dest","call","current","j","base","props","staticProps","parent","child","hasOwnProperty","qutils","config","defaults","contentType","headers","statusCode",404,"parameterParser","xhrFields","withCredentials","transportOptions","d","isFunction","connect","method","connectOptions","type","ALLOWED_TO_BE_FUNCTIONS","logLevel","console","log","oldSuccessFn","response","ajaxStatus","ajaxReq","beforeSend","xhr","settings","requestUrl","ajax","publicAPI","ajaxOptions","splitGet","post","patch","put","delete","delimiter","head","epiVersion","API_PROTOCOL","HOST_API_MAPPING","forio.com","foriodev.com","publicExports","protocol","host","window","location","appPath","path","pathname","accountPath","accnt","projectPath","prj","versionPath","isLocalhost","getAPIPath","PROJECT_APIS","apiPath","urlService","serviceOptions","server","setEnv","env","property","set","ConfigService","StorageFactory","rutil","_pick","TransportFactory","VariablesService","synchronous","token","account","project","filter","autoRestore","urlConfig","getFilterURL","addAutoRestoreHeader","isFilterRunId","autorestoreOpts","X-AutoRestore","Authorization","setFilterOrThrowError","Error","publicAsyncAPI","create","createOptions","runApiParams","model","outputModifier","load","runID","filters","save","attributes","do","opsArgs","postOptions","prms","serial","opParams","me","$d","doSingleOp","op","shift","parallel","queue","i","done","publicSyncAPI","getCurrentConfig","vs","runService","getContents","filePath","folderType","getURL","attrs","root","domain","q","saveAs","remove","keys","userName","password","login","resp","status","statusMessage","postParams","logout","apiBase","assignmentEndpoint","apiEndpoint","projectEndpoint","group","setIdFilterOrThrowError","validateModelOrThrowError","worldApiParams","update","whitelist","updateOptions","deleteOptions","updateConfig","getOptions","getWorldsForUser","userId","worldId","addUsers","users","u","updateUser","user","patchOptions","removeUser","getCurrentRunId","getCurrentWorldForUser","groupName","worlds","sort","a","b","Date","lastModified","currentWorld","deleteRun","newRunForWorld","currentRunOptions","autoAssign","opt","maxUsers","getProjectSettings","parseRunIdOrError","runId","replay","replayOptions","action","clone","toQFilter","toIdFilters","getFilters","threshold","getById","groupId","getFinalParams","patchUserActiveField","active","getGroupsForUser","isString","objParams","getParms","getGroupDetails","makeUserActive","makeUserInactive","keyNames","session","parse","EPI_SESSION_KEY","EPI_COOKIE_KEY","scope","fullUrl","processData","assetApiParams","scopeConfig","validateFilename","filename","validateUrlParams","partKeys","buildUrl","parts","upload","toLowerCase","FormData","urlOptions","getServiceOptions","files","fullPathFiles","file","assetUrl","setOptions","document","cookie","encodeURIComponent","cookieReg","RegExp","decodeURIComponent","remOptions","destroy","aKeys","nIdx","cookieKey","RunService","validFilter","saved","getRuns","loadVariables","meta","_getService","archive","getRun","patchRunService","patched","orig","reservedOps","Object","specialOperations","StrategyCtor","strategiesMap","reset","runServiceOptions","saveSession","userInfo","serialized","auth_token","getSession","authAdapter","AuthAdapter","MemberAdapter","Buffer","_findUserInGroup","members","adapterOptions","outSuccess","outError","accountName","projectName","decodeToken","encoded","decode","atob","toString","handleGroupError","message","statusText","handleSuccess","access_token","userGroupOpts","getUserGroups","user_id","memberInfo","auth","userGroups","groupSelection","sessionInfo","filteredGroups","grep","resGroup","sessionInfoWithGroup","isFac","role","removeCookieFn","getToken","memberAdapter","getCurrentUserSessionInfo","buildStrategy","worldApi","WorldApi","world","_auth","getCurrentWorld","getCurrentRun","getAndRestoreLatestRun","currentWorldId","runOpts","rm","curUserId","curGroupName","getFromSettingsOrSessionOrError","sessionKeyName","EpicenterChannelManager","defaultCometOptions","urlOpts","getGroupChannel","baseTopic","getChannel","getWorldChannel","worldid","getUserChannel","userid","getPresenceChannel","channel","lastPingTime","PING_INTERVAL","subscribe","notification","incomingUserId","trigger","online","valueOf","setInterval","publish","now","getDataChannel","collection","oldsubs","topic","callback","context","callbackWithCleanData","payload","subType","date","actualData","topicResolver","channelOptions","makeName","channelName","newName","topics","subscriptionIds","opts","batch","returnObjs","warn","unsubscribe","on","event","off","ConditionalStrategy","Strategy","createIf","setRunInSession","sessionKey","sessionStore","makeSeq","Base","SessionStore","UrlService","STRATEGY_SESSION_KEY","condition","runOptions","runOptionsWithScope","userSession","freshlyCreated","runSession","_loadAndCheck","shouldCreate","msg","getResponseHeader","initialized","cometd","websocketEnabled","shareConnection","currentSubscriptions","_cometd","Cometd","isConnected","connectionBroken","connectionSucceeded","configure","addListener","wasConnected","successful","subs","resubscribe","handshake","subid","unsubs","removed","new-if-initialized","new-if-persisted","new-if-missing","always-new","multiplayer","persistent-single-player","none","typedArraySupport","Bar","Uint8Array","foo","subarray","byteLength","e","kMaxLength","TYPED_ARRAY_SUPPORT","fromNumber","fromString","fromObject","that","allocate","checked","string","encoding","write","object","isBuffer","fromBuffer","fromArray","TypeError","ArrayBuffer","buffer","fromTypedArray","fromArrayBuffer","fromArrayLike","fromJsonObject","copy","array","_augment","__proto__","_isBuffer","fromPool","poolSize","rootParent","RangeError","SlowBuffer","subject","buf","len","loweredCase","utf8ToBytes","base64ToBytes","slowToString","end","Infinity","hexSlice","utf8Slice","asciiSlice","binarySlice","base64Slice","utf16leSlice","hexWrite","offset","Number","remaining","strLen","parsed","parseInt","substr","isNaN","utf8Write","blitBuffer","asciiWrite","asciiToBytes","binaryWrite","base64Write","ucs2Write","utf16leToBytes","base64","fromByteArray","Math","min","firstByte","codePoint","bytesPerSequence","secondByte","thirdByte","fourthByte","tempCodePoint","decodeCodePointsArray","codePoints","MAX_ARGUMENTS_LENGTH","fromCharCode","ret","out","toHex","bytes","checkOffset","ext","checkInt","max","objectWriteUInt16","littleEndian","objectWriteUInt32","checkIEEE754","writeFloat","noAssert","ieee754","writeDouble","base64clean","str","stringtrim","INVALID_BASE64_RE","n","units","leadSurrogate","charCodeAt","byteArray","c","hi","lo","toByteArray","src","dst","INSPECT_MAX_BYTES","compare","x","y","isEncoding","pos","item","equals","inspect","match","byteOffset","arrayIndexOf","foundIndex","readUInt8","v","writeUInt8","isFinite","swap","toJSON","_arr","newBuf","sliceLen","readUIntLE","mul","readUIntBE","readUInt16LE","readUInt16BE","readUInt32LE","readUInt32BE","readIntLE","pow","readIntBE","readInt8","readInt16LE","readInt16BE","readInt32LE","readInt32BE","readFloatLE","read","readFloatBE","readDoubleLE","readDoubleBE","writeUIntLE","writeUIntBE","floor","writeUInt16LE","writeUInt16BE","writeUInt32LE","writeUInt32BE","writeIntLE","limit","sub","writeIntBE","writeInt8","writeInt16LE","writeInt16BE","writeInt32LE","writeInt32BE","writeFloatLE","writeFloatBE","writeDoubleLE","writeDoubleBE","target","targetStart","_set","fill","toArrayBuffer","BP","toLocaleString","IdentityStrategy","WorldApiAdapter","_loadRun","loadRunFromWorld","serverError","StateApi","_store","stateApi","_restoreRun","_getAllRuns","user.id","scope.group","dateComp","latestRun","shouldReplay","isLE","mLen","nBytes","m","eLen","eMax","eBias","nBits","s","NaN","rt","abs","LN2","lookup","elt","code","PLUS","PLUS_URL_SAFE","SLASH","SLASH_URL_SAFE","NUMBER","UPPER","LOWER","b64ToByteArray","b64","L","l","tmp","placeHolders","Arr","uint8ToBase64","uint8","encode","num","tripletToBase64","temp","extraBytes","output","base64js"],"mappings":"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","file":"bundle.js","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && url.length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = '?include='.length;\n var variable = include.pop();\n while (variable) {\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + variable.length + 1 < diff) {\n currIncludes.push(variable);\n currLength += variable.length + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + variable.length;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ##File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n // config || (config = configService.get());\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || store.get('epicenter.token') || '',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: '',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {String} `folderType` One of Model|Static|Node\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, folderType, options) {\n var path = folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ##Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * ##Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: '',\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n domain: 'forio.com',\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ##Authentication API Service\n *\n * The Authentication API Service provides methods for logging in and logging out. On login, this service creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n * auth.logout();\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n /**\n * Logs user out from specified accounts.\n * Epicenter logout is not implemented yet, added a dummy promise that gets automatically resolved.\n *\n * **Example**\n *\n * auth.logout();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ##World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n $.extend(params, _pick(serviceOptions, ['account', 'project', 'group']));\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ##State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ##User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ##Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: '',\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar keyNames = require('../managers/key-names');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n var session = JSON.parse(store.get(keyNames.EPI_SESSION_KEY) || '{}');\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get(keyNames.EPI_COOKIE_KEY) || '',\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: session.userId,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n var serviceOptions = $.extend(true, {}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.forio.com'\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n\n document.cookie = encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookieReg = new RegExp('(?:(?:^|.*;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$');\n var val = document.cookie.replace(cookieReg, '$1');\n val = decodeURIComponent(val) || null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n\n document.cookie = encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var aKeys = document.cookie.replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* ####Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar ConfigService = require('../service/configuration-service');\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar StorageFactory = require('../store/store-factory');\nvar Buffer = require('buffer').Buffer;\nvar keyNames = require('./key-names');\n\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY;\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar store;\nvar token;\nvar session;\n\nfunction saveSession(userInfo, store) {\n var serialized = JSON.stringify(userInfo);\n store.set(EPI_SESSION_KEY, serialized);\n\n //jshint camelcase: false\n //jscs:disable\n store.set(EPI_COOKIE_KEY, userInfo.auth_token);\n}\n\nfunction getSession(store) {\n var session = store.get(EPI_SESSION_KEY) || '{}';\n return JSON.parse(session);\n}\n\nfunction AuthManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n var urlConfig = new ConfigService(this.options).get('server');\n if (!this.options.account) {\n this.options.account = urlConfig.accountPath;\n }\n\n // null might specified to disable project filtering\n if (this.options.project === undefined) {\n this.options.project = urlConfig.projectPath;\n }\n\n this.store = new StorageFactory(this.options.store);\n session = getSession(this.store);\n token = this.store.get(EPI_COOKIE_KEY) || '';\n //jshint camelcase: false\n //jscs:disable\n this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token });\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(memberInfo, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n var groupSelection = group.groupId;\n data.groupSelection[adapterOptions.project] = groupSelection;\n var sessionInfoWithGroup = $.extend({}, sessionInfo, {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n });\n saveSession(sessionInfoWithGroup, _this.store);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n }).fail($d.reject);\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var adapterOptions = $.extend(true, { token: token }, this.options, options);\n\n var removeCookieFn = function (response) {\n store.remove(EPI_COOKIE_KEY, adapterOptions);\n store.remove(EPI_SESSION_KEY, adapterOptions);\n token = '';\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = $.extend(true, this.options, options);\n\n var $d = $.Deferred();\n if (token) {\n $d.resolve(token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = $.extend(true, { success: $.noop }, this.options, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return getSession(this.store, options);\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `server` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `server.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `server.project` Epicenter project id.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\n\nvar AuthManager = require('./auth-manager');\n\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n var userInfo = session.getCurrentUserSessionInfo();\n\n var defaults = {\n account: userInfo.account,\n project: userInfo.project,\n };\n var defaultCometOptions = $.extend(true, {}, defaults, userInfo, options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getDataChannel('survey-responses');\n * gc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionStore = require('../../store/store-factory');\nvar classFrom = require('../../util/inherit');\nvar UrlService = require('../../service/url-config-service');\nvar AuthManager = require('../auth-manager');\n\nvar sessionStore = new SessionStore({});\nvar urlService = new UrlService();\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, path) {\n if (!path) {\n if (!urlService.isLocalhost()) {\n path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/');\n // make sure we don't get consecuteive '/' so we have a valid path for the session\n path = path.replace(/\\/{2,}/g,'/');\n } else {\n path = '';\n }\n }\n // set the seesionKey for the run\n sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path });\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.options.path);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession);\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","'use strict';\n\nmodule.exports = {\n EPI_COOKIE_KEY: 'epicenter.project.token',\n EPI_SESSION_KEY: 'epicenter.user.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","'use strict';\n\nvar Channel = require('../service/channel-service');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n }\n };\n var defaultCometOptions = $.extend(true, {}, defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake();\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('is-array')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\nBuffer.poolSize = 8192 // not used by this implementation\n\nvar rootParent = {}\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property\n * on objects.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\nfunction typedArraySupport () {\n function Bar () {}\n try {\n var arr = new Uint8Array(1)\n arr.foo = function () { return 42 }\n arr.constructor = Bar\n return arr.foo() === 42 && // typed array instances can be augmented\n arr.constructor === Bar && // constructor can be set\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\n/**\n * Class: Buffer\n * =============\n *\n * The Buffer constructor returns instances of `Uint8Array` that are augmented\n * with function properties for all the node `Buffer` API functions. We use\n * `Uint8Array` so that square bracket notation works as expected -- it returns\n * a single octet.\n *\n * By augmenting the instances, we can avoid modifying the `Uint8Array`\n * prototype.\n */\nfunction Buffer (arg) {\n if (!(this instanceof Buffer)) {\n // Avoid going through an ArgumentsAdaptorTrampoline in the common case.\n if (arguments.length > 1) return new Buffer(arg, arguments[1])\n return new Buffer(arg)\n }\n\n this.length = 0\n this.parent = undefined\n\n // Common case.\n if (typeof arg === 'number') {\n return fromNumber(this, arg)\n }\n\n // Slightly less common case.\n if (typeof arg === 'string') {\n return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')\n }\n\n // Unusual.\n return fromObject(this, arg)\n}\n\nfunction fromNumber (that, length) {\n that = allocate(that, length < 0 ? 0 : checked(length) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < length; i++) {\n that[i] = 0\n }\n }\n return that\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'\n\n // Assumption: byteLength() return value is always < kMaxLength.\n var length = byteLength(string, encoding) | 0\n that = allocate(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromObject (that, object) {\n if (Buffer.isBuffer(object)) return fromBuffer(that, object)\n\n if (isArray(object)) return fromArray(that, object)\n\n if (object == null) {\n throw new TypeError('must start with number, buffer, array or string')\n }\n\n if (typeof ArrayBuffer !== 'undefined') {\n if (object.buffer instanceof ArrayBuffer) {\n return fromTypedArray(that, object)\n }\n if (object instanceof ArrayBuffer) {\n return fromArrayBuffer(that, object)\n }\n }\n\n if (object.length) return fromArrayLike(that, object)\n\n return fromJsonObject(that, object)\n}\n\nfunction fromBuffer (that, buffer) {\n var length = checked(buffer.length) | 0\n that = allocate(that, length)\n buffer.copy(that, 0, 0, length)\n return that\n}\n\nfunction fromArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Duplicate of fromArray() to keep fromArray() monomorphic.\nfunction fromTypedArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n // Truncating the elements is probably not what people expect from typed\n // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior\n // of the old Buffer constructor.\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n array.byteLength\n that = Buffer._augment(new Uint8Array(array))\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromTypedArray(that, new Uint8Array(array))\n }\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.\n// Returns a zero-length buffer for inputs that don't conform to the spec.\nfunction fromJsonObject (that, object) {\n var array\n var length = 0\n\n if (object.type === 'Buffer' && isArray(object.data)) {\n array = object.data\n length = checked(array.length) | 0\n }\n that = allocate(that, length)\n\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n}\n\nfunction allocate (that, length) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = Buffer._augment(new Uint8Array(length))\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that.length = length\n that._isBuffer = true\n }\n\n var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1\n if (fromPool) that.parent = rootParent\n\n return that\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (subject, encoding) {\n if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)\n\n var buf = new Buffer(subject, encoding)\n delete buf.parent\n return buf\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n var i = 0\n var len = Math.min(x, y)\n while (i < len) {\n if (a[i] !== b[i]) break\n\n ++i\n }\n\n if (i !== len) {\n x = a[i]\n y = b[i]\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')\n\n if (list.length === 0) {\n return new Buffer(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; i++) {\n length += list[i].length\n }\n }\n\n var buf = new Buffer(length)\n var pos = 0\n for (i = 0; i < list.length; i++) {\n var item = list[i]\n item.copy(buf, pos)\n pos += item.length\n }\n return buf\n}\n\nfunction byteLength (string, encoding) {\n if (typeof string !== 'string') string = '' + string\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n // Deprecated\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\n// pre-set for values that may exist in the future\nBuffer.prototype.length = undefined\nBuffer.prototype.parent = undefined\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n start = start | 0\n end = end === undefined || end === Infinity ? this.length : end | 0\n\n if (!encoding) encoding = 'utf8'\n if (start < 0) start = 0\n if (end > this.length) end = this.length\n if (end <= start) return ''\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return 0\n return Buffer.compare(this, b)\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset) {\n if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff\n else if (byteOffset < -0x80000000) byteOffset = -0x80000000\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n if (val.length === 0) return -1 // special case: looking for empty string always fails\n return String.prototype.indexOf.call(this, val, byteOffset)\n }\n if (Buffer.isBuffer(val)) {\n return arrayIndexOf(this, val, byteOffset)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset)\n }\n\n function arrayIndexOf (arr, val, byteOffset) {\n var foundIndex = -1\n for (var i = 0; byteOffset + i < arr.length; i++) {\n if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex\n } else {\n foundIndex = -1\n }\n }\n return -1\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\n// `get` is deprecated\nBuffer.prototype.get = function get (offset) {\n console.log('.get() is deprecated. Access using array indexes instead.')\n return this.readUInt8(offset)\n}\n\n// `set` is deprecated\nBuffer.prototype.set = function set (v, offset) {\n console.log('.set() is deprecated. Access using array indexes instead.')\n return this.writeUInt8(v, offset)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; i++) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) throw new Error('Invalid hex string')\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n var swap = encoding\n encoding = offset\n offset = length | 0\n length = swap\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; i++) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = Buffer._augment(this.subarray(start, end))\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; i++) {\n newBuf[i] = this[i + start]\n }\n }\n\n if (newBuf.length) newBuf.parent = this.parent || this\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n if (offset < 0) throw new RangeError('index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; i--) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; i++) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n target._set(this.subarray(start, start + len), targetStart)\n }\n\n return len\n}\n\n// fill(value, start=0, end=buffer.length)\nBuffer.prototype.fill = function fill (value, start, end) {\n if (!value) value = 0\n if (!start) start = 0\n if (!end) end = this.length\n\n if (end < start) throw new RangeError('end < start')\n\n // Fill 0 bytes; we're done\n if (end === start) return\n if (this.length === 0) return\n\n if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')\n if (end < 0 || end > this.length) throw new RangeError('end out of bounds')\n\n var i\n if (typeof value === 'number') {\n for (i = start; i < end; i++) {\n this[i] = value\n }\n } else {\n var bytes = utf8ToBytes(value.toString())\n var len = bytes.length\n for (i = start; i < end; i++) {\n this[i] = bytes[i % len]\n }\n }\n\n return this\n}\n\n/**\n * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.\n * Added in Node 0.12. Only available in browsers that support ArrayBuffer.\n */\nBuffer.prototype.toArrayBuffer = function toArrayBuffer () {\n if (typeof Uint8Array !== 'undefined') {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n return (new Buffer(this)).buffer\n } else {\n var buf = new Uint8Array(this.length)\n for (var i = 0, len = buf.length; i < len; i += 1) {\n buf[i] = this[i]\n }\n return buf.buffer\n }\n } else {\n throw new TypeError('Buffer.toArrayBuffer not supported in this browser')\n }\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar BP = Buffer.prototype\n\n/**\n * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods\n */\nBuffer._augment = function _augment (arr) {\n arr.constructor = Buffer\n arr._isBuffer = true\n\n // save reference to original Uint8Array set method before overwriting\n arr._set = arr.set\n\n // deprecated\n arr.get = BP.get\n arr.set = BP.set\n\n arr.write = BP.write\n arr.toString = BP.toString\n arr.toLocaleString = BP.toString\n arr.toJSON = BP.toJSON\n arr.equals = BP.equals\n arr.compare = BP.compare\n arr.indexOf = BP.indexOf\n arr.copy = BP.copy\n arr.slice = BP.slice\n arr.readUIntLE = BP.readUIntLE\n arr.readUIntBE = BP.readUIntBE\n arr.readUInt8 = BP.readUInt8\n arr.readUInt16LE = BP.readUInt16LE\n arr.readUInt16BE = BP.readUInt16BE\n arr.readUInt32LE = BP.readUInt32LE\n arr.readUInt32BE = BP.readUInt32BE\n arr.readIntLE = BP.readIntLE\n arr.readIntBE = BP.readIntBE\n arr.readInt8 = BP.readInt8\n arr.readInt16LE = BP.readInt16LE\n arr.readInt16BE = BP.readInt16BE\n arr.readInt32LE = BP.readInt32LE\n arr.readInt32BE = BP.readInt32BE\n arr.readFloatLE = BP.readFloatLE\n arr.readFloatBE = BP.readFloatBE\n arr.readDoubleLE = BP.readDoubleLE\n arr.readDoubleBE = BP.readDoubleBE\n arr.writeUInt8 = BP.writeUInt8\n arr.writeUIntLE = BP.writeUIntLE\n arr.writeUIntBE = BP.writeUIntBE\n arr.writeUInt16LE = BP.writeUInt16LE\n arr.writeUInt16BE = BP.writeUInt16BE\n arr.writeUInt32LE = BP.writeUInt32LE\n arr.writeUInt32BE = BP.writeUInt32BE\n arr.writeIntLE = BP.writeIntLE\n arr.writeIntBE = BP.writeIntBE\n arr.writeInt8 = BP.writeInt8\n arr.writeInt16LE = BP.writeInt16LE\n arr.writeInt16BE = BP.writeInt16BE\n arr.writeInt32LE = BP.writeInt32LE\n arr.writeInt32BE = BP.writeInt32BE\n arr.writeFloatLE = BP.writeFloatLE\n arr.writeFloatBE = BP.writeFloatBE\n arr.writeDoubleLE = BP.writeDoubleLE\n arr.writeDoubleBE = BP.writeDoubleBE\n arr.fill = BP.fill\n arr.inspect = BP.inspect\n arr.toArrayBuffer = BP.toArrayBuffer\n\n return arr\n}\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; i++) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; i++) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n;(function (exports) {\n\t'use strict';\n\n var Arr = (typeof Uint8Array !== 'undefined')\n ? Uint8Array\n : Array\n\n\tvar PLUS = '+'.charCodeAt(0)\n\tvar SLASH = '/'.charCodeAt(0)\n\tvar NUMBER = '0'.charCodeAt(0)\n\tvar LOWER = 'a'.charCodeAt(0)\n\tvar UPPER = 'A'.charCodeAt(0)\n\tvar PLUS_URL_SAFE = '-'.charCodeAt(0)\n\tvar SLASH_URL_SAFE = '_'.charCodeAt(0)\n\n\tfunction decode (elt) {\n\t\tvar code = elt.charCodeAt(0)\n\t\tif (code === PLUS ||\n\t\t code === PLUS_URL_SAFE)\n\t\t\treturn 62 // '+'\n\t\tif (code === SLASH ||\n\t\t code === SLASH_URL_SAFE)\n\t\t\treturn 63 // '/'\n\t\tif (code < NUMBER)\n\t\t\treturn -1 //no match\n\t\tif (code < NUMBER + 10)\n\t\t\treturn code - NUMBER + 26 + 26\n\t\tif (code < UPPER + 26)\n\t\t\treturn code - UPPER\n\t\tif (code < LOWER + 26)\n\t\t\treturn code - LOWER + 26\n\t}\n\n\tfunction b64ToByteArray (b64) {\n\t\tvar i, j, l, tmp, placeHolders, arr\n\n\t\tif (b64.length % 4 > 0) {\n\t\t\tthrow new Error('Invalid string. Length must be a multiple of 4')\n\t\t}\n\n\t\t// the number of equal signs (place holders)\n\t\t// if there are two placeholders, than the two characters before it\n\t\t// represent one byte\n\t\t// if there is only one, then the three characters before it represent 2 bytes\n\t\t// this is just a cheap hack to not do indexOf twice\n\t\tvar len = b64.length\n\t\tplaceHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0\n\n\t\t// base64 is 4/3 + up to two characters of the original data\n\t\tarr = new Arr(b64.length * 3 / 4 - placeHolders)\n\n\t\t// if there are placeholders, only get up to the last complete 4 chars\n\t\tl = placeHolders > 0 ? b64.length - 4 : b64.length\n\n\t\tvar L = 0\n\n\t\tfunction push (v) {\n\t\t\tarr[L++] = v\n\t\t}\n\n\t\tfor (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))\n\t\t\tpush((tmp & 0xFF0000) >> 16)\n\t\t\tpush((tmp & 0xFF00) >> 8)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\tif (placeHolders === 2) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)\n\t\t\tpush(tmp & 0xFF)\n\t\t} else if (placeHolders === 1) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)\n\t\t\tpush((tmp >> 8) & 0xFF)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\treturn arr\n\t}\n\n\tfunction uint8ToBase64 (uint8) {\n\t\tvar i,\n\t\t\textraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes\n\t\t\toutput = \"\",\n\t\t\ttemp, length\n\n\t\tfunction encode (num) {\n\t\t\treturn lookup.charAt(num)\n\t\t}\n\n\t\tfunction tripletToBase64 (num) {\n\t\t\treturn encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)\n\t\t}\n\n\t\t// go through the array every three bytes, we'll deal with trailing stuff later\n\t\tfor (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n\t\t\ttemp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n\t\t\toutput += tripletToBase64(temp)\n\t\t}\n\n\t\t// pad the end with zeros, but make sure to not forget the extra bytes\n\t\tswitch (extraBytes) {\n\t\t\tcase 1:\n\t\t\t\ttemp = uint8[uint8.length - 1]\n\t\t\t\toutput += encode(temp >> 2)\n\t\t\t\toutput += encode((temp << 4) & 0x3F)\n\t\t\t\toutput += '=='\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\ttemp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])\n\t\t\t\toutput += encode(temp >> 10)\n\t\t\t\toutput += encode((temp >> 4) & 0x3F)\n\t\t\t\toutput += encode((temp << 2) & 0x3F)\n\t\t\t\toutput += '='\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn output\n\t}\n\n\texports.toByteArray = b64ToByteArray\n\texports.fromByteArray = uint8ToBase64\n}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))\n","\n/**\n * isArray\n */\n\nvar isArray = Array.isArray;\n\n/**\n * toString\n */\n\nvar str = Object.prototype.toString;\n\n/**\n * Whether or not the given `val`\n * is an array.\n *\n * example:\n *\n * isArray([]);\n * // > true\n * isArray(arguments);\n * // > false\n * isArray('');\n * // > false\n *\n * @param {mixed} val\n * @return {bool}\n */\n\nmodule.exports = isArray || function (val) {\n return !! val && '[object Array]' == str.call(val);\n};\n"]} \ No newline at end of file From 19bbcab8d7a5ff1636d961c2f1421ff85c98664f Mon Sep 17 00:00:00 2001 From: john zhang Date: Fri, 26 Feb 2016 16:42:01 -0800 Subject: [PATCH 10/14] add user is local tests for authmanager cookie setting to work with dev users --- dist/components/assignment/assignment.js | 2 +- src/managers/auth-manager.js | 4 +++- tests/spec/test-auth-manager.js | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dist/components/assignment/assignment.js b/dist/components/assignment/assignment.js index 74ae582d..947e5bfa 100644 --- a/dist/components/assignment/assignment.js +++ b/dist/components/assignment/assignment.js @@ -1231,4 +1231,4 @@ module.exports = function (base, props, staticProps) { }; },{}]},{},[6]) -//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Fzc2lnbm1lbnQtcm93LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9hc3NpZ25tZW50LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9iYXNlLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Jhc2UtbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2RlZmF1bHRzLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9pbmRleC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvcHJvamVjdC1tb2RlbC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvc2VydmljZS1sb2NhdG9yLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy90ZW1wbGF0ZXMuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXItbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXJzLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3dvcmxkLW1vZGVsLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy93b3JsZHMtY29sbGVjdGlvbi5qcyIsInNyYy91dGlsL2FqYXgtcXVldWUuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCc7XG5cbnZhciB0ZW1wbGF0ZXMgPSByZXF1aXJlKCcuL3RlbXBsYXRlcycpO1xuXG52YXIgQXNzaWdubWVudFJvdyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy4kZWwgPSAkKCc8dHI+Jyk7XG4gICAgdGhpcy5lbCA9IHRoaXMuJGVsWzBdO1xuICAgIHRoaXMuJCA9IF8ucGFydGlhbFJpZ2h0KCQsIHRoaXMuJGVsKTtcblxuICAgIHRoaXMubW9kZWwgPSBvcHRpb25zLm1vZGVsO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy53b3JsZHMgPSBvcHRpb25zLndvcmxkcztcbiAgICB0aGlzLnByb2plY3QgPSBvcHRpb25zLnByb2plY3Q7XG5cbiAgICBfLmJpbmRBbGwodGhpcywgWydzZXRFZGl0TW9kZScsICdyZW1vdmVFZGl0TW9kZScsICdzYXZlRWRpdCcsICdjYW5jZWxFZGl0JywgJ3VwZGF0ZURhdGEnXSk7XG5cbiAgICB0aGlzLmJpbmRFdmVudHMoKTtcblxufTtcblxuXy5leHRlbmQoQXNzaWdubWVudFJvdy5wcm90b3R5cGUsIHtcblxuICAgIHRlbXBsYXRlOiB0ZW1wbGF0ZXNbJ3VzZXItcm93J10sXG5cbiAgICBlZGl0VGVtcGxhdGU6IHRlbXBsYXRlc1snZWRpdC11c2VyLXJvdyddLFxuXG4gICAgYmluZEV2ZW50czogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnYnV0dG9uLmVkaXQnLCB0aGlzLnNldEVkaXRNb2RlKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2J1dHRvbi5zYXZlJywgdGhpcy5zYXZlRWRpdCk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICdidXR0b24uY2FuY2VsJywgdGhpcy5jYW5jZWxFZGl0KTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9mZignY2xpY2snLCBudWxsLCBudWxsKTtcbiAgICAgICAgLy8gdGhpcyBvbmx5IGdpdmVzIGEgZGVsYXkgdG8gcmVtb3ZlIHRoZSB0clxuICAgICAgICAvLyBhbmltYXRpb24gb2YgaGVpZ2h0IG9mIHRoZSB0ciBkb2VzIG5vdCB3b3JrXG4gICAgICAgIHRoaXMuJCgnOmNoZWNrYm94JykuYXR0cignY2hlY2tlZCcsIGZhbHNlKTtcbiAgICAgICAgdGhpcy4kZWxcbiAgICAgICAgICAgIC5jc3MoeyBvcGFjaXR5OiAwLjMgfSlcbiAgICAgICAgICAgIC5hbmltYXRlKHsgaGVpZ2h0OiAwIH0sIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMzAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIG1ha2VJbmFjdGl2ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tb2RlbC5tYWtlSW5hY3RpdmUoKTtcbiAgICB9LFxuXG4gICAgc2V0RWRpdE1vZGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5tb2RlbC5zZXQoJ2VkaXQtbW9kZScsIHRydWUpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICByZW1vdmVFZGl0TW9kZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLm1vZGVsLnNldCgnZWRpdC1tb2RlJywgZmFsc2UpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICBzYXZlRWRpdDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB0aGlzLnVwZGF0ZURhdGEoKTtcbiAgICAgICAgdGhpcy53b3JsZHNcbiAgICAgICAgICAgIC51cGRhdGVVc2VyKHRoaXMubW9kZWwpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMucmVtb3ZlRWRpdE1vZGUoKTtcbiAgICAgICAgICAgICAgICBfdGhpcy4kZWwudHJpZ2dlcigndXBkYXRlJywgX3RoaXMpO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGNhbmNlbEVkaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVFZGl0TW9kZSgpO1xuICAgIH0sXG5cbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHRlbXBsID0gdGhpcy5tb2RlbC5nZXQoJ2VkaXQtbW9kZScpID8gdGhpcy5lZGl0VGVtcGxhdGUgOiB0aGlzLnRlbXBsYXRlO1xuICAgICAgICB2YXIgdm0gPSBfLmV4dGVuZCh7XG4gICAgICAgICAgICByb2xlczogdGhpcy5wcm9qZWN0LmdldCgncm9sZXMnKSxcbiAgICAgICAgICAgIG9wdGlvbmFsUm9sZXM6IHRoaXMucHJvamVjdC5nZXQoJ29wdGlvbmFsUm9sZXMnKSxcbiAgICAgICAgICAgIHdvcmxkczogdGhpcy53b3JsZHMuZ2V0V29ybGROYW1lcygpLFxuICAgICAgICAgICAgbmV3V29ybGQ6IHRoaXMud29ybGRzLmdldE5leHRXb3JsZE5hbWUoKVxuICAgICAgICB9LCB0aGlzLm1vZGVsLnRvSlNPTigpKTtcblxuICAgICAgICB0aGlzLiRlbC5odG1sKHRlbXBsKHZtKSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIHVwZGF0ZURhdGE6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdGhpcy4kKCdbZGF0YS1maWVsZF0nKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBlbCA9ICQodGhpcyk7XG4gICAgICAgICAgICB2YXIgZmllbGQgPSBlbC5kYXRhKCdmaWVsZCcpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IGVsLnZhbCgpO1xuXG4gICAgICAgICAgICBfdGhpcy5tb2RlbC5zZXQoZmllbGQsIHZhbCk7XG4gICAgICAgIH0pO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQXNzaWdubWVudFJvdzsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBVc2Vyc0NvbGxlY3Rpb24gPSByZXF1aXJlKCcuL3VzZXJzLWNvbGxlY3Rpb24nKTtcbnZhciBXb3JsZHNDb2xsZWN0aW9uID0gcmVxdWlyZSgnLi93b3JsZHMtY29sbGVjdGlvbicpO1xudmFyIFByb2plY3RNb2RlbCA9IHJlcXVpcmUoJy4vcHJvamVjdC1tb2RlbCcpO1xudmFyIEFzc2lnbmVtbnRSb3cgPSByZXF1aXJlKCcuL2Fzc2lnbm1lbnQtcm93Jyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIEFqYXhRdWV1ZSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvYWpheC1xdWV1ZScpO1xuXG5mdW5jdGlvbiBzZXRFbnZpcm9ubWVudChvcHRpb25zKSB7XG4gICAgZW52LnNldChfLm9taXQob3B0aW9ucywgJ2VsJykpO1xufVxuXG52YXIgQXNzaWdubWVudCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgc2V0RW52aXJvbm1lbnQob3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplKG9wdGlvbnMpO1xufTtcblxuQXNzaWdubWVudC5wcm90b3R5cGUgPSB7XG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLmVsID0gdHlwZW9mIG9wdGlvbnMuZWwgPT09ICdzdHJpbmcnID8gJChvcHRpb25zLmVsKVswXSA6IG9wdGlvbnMuZWw7XG4gICAgICAgIHRoaXMuJGVsID0gJCh0aGlzLmVsKTtcbiAgICAgICAgdGhpcy4kID0gXy5wYXJ0aWFsUmlnaHQoJCwgdGhpcy5lbCk7XG5cbiAgICAgICAgdGhpcy51c2VycyA9IG5ldyBVc2Vyc0NvbGxlY3Rpb24oKTtcbiAgICAgICAgdGhpcy53b3JsZHMgPSBuZXcgV29ybGRzQ29sbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnByb2plY3QgPSBuZXcgUHJvamVjdE1vZGVsKCk7XG5cbiAgICAgICAgXy5iaW5kQWxsKHRoaXMsIFsncmVuZGVyJywgJ3JlbmRlclRhYmxlJywgJ3RvZ2dsZUNvbnRyb2xscycsICdzYXZlRWRpdCcsICdzZWxlY3RBbGwnLCAndXNhc3NpZ25TZWxlY3RlZCcsICdfc2hvd1VwZGF0aW5nJywgJ19oaWRlVXBkYXRpbmcnLCAnYXV0b0Fzc2lnbkFsbCcsICdtYWtlVXNlckluYWN0aXZlJ10pO1xuXG4gICAgICAgIHRoaXMuYmluZEV2ZW50cygpO1xuICAgIH0sXG5cbiAgICBiaW5kRXZlbnRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9uKCd1cGRhdGUnLCAndHInLCB0aGlzLnNhdmVFZGl0KTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2lucHV0OmNoZWNrYm94Om5vdCgjc2VsZWN0LWFsbCknLCB0aGlzLnRvZ2dsZUNvbnRyb2xscyk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICcjc2VsZWN0LWFsbCcsIHRoaXMuc2VsZWN0QWxsKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy51bmFzc2lnbi11c2VyJywgdGhpcy51c2Fzc2lnblNlbGVjdGVkKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy5hdXRvLWFzc2lnbi1hbGwnLCB0aGlzLmF1dG9Bc3NpZ25BbGwpO1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnLm1ha2UtdXNlci1pbmFjdGl2ZScsIHRoaXMubWFrZVVzZXJJbmFjdGl2ZSk7XG4gICAgfSxcblxuICAgIGxvYWQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB2YXIgam9pbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLnNldFVzZXJzQ29sbGVjdGlvbih0aGlzLnVzZXJzKTtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLmpvaW5Vc2VycygpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHJldHVybiAkLndoZW4oXG4gICAgICAgICAgICB0aGlzLndvcmxkcy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy51c2Vycy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy5wcm9qZWN0LmZldGNoKClcbiAgICAgICAgKS50aGVuKGpvaW4pO1xuXG4gICAgfSxcblxuICAgIHNhdmVFZGl0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMud29ybGRzLmZldGNoKClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ29udHJvbHMoKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGF1dG9Bc3NpZ25BbGw6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG4gICAgICAgIHZhciBtYXhVc2VycyA9ICt0aGlzLiQoJyNtYXgtdXNlcnMnKS52YWwoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMud29ybGRzLmF1dG9Bc3NpZ25BbGwoeyBtYXhVc2VyczogbWF4VXNlcnMgfSlcbiAgICAgICAgICAgIC5kb25lKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC5mYWlsKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9LFxuXG4gICAgZ2V0U2VsZWN0ZWRJZHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuJCgndGJvZHkgOmNoZWNrYm94OmNoZWNrZWQnKS5tYXAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICQodGhpcykuZGF0YSgnaWQnKTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGZpbmRSb3dWaWV3czogZnVuY3Rpb24gKGlkcykge1xuICAgICAgICByZXR1cm4gXy5tYXAoaWRzLCBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJvd1ZpZXdzW2lkXTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfSxcblxuICAgIHVuYXNzaWduVXNlcnM6IGZ1bmN0aW9uIChpZHMpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIGZvciBub3cgd2UgbmVlZCB0byBzZXF1ZW5jZSB0aGUgY2FsbHMgdG8gdW5hc3NpZ24gdXNlcnMgZnJvbSB3b3JsZHNcbiAgICAgICAgdmFyIHF1ZXVlID0gbmV3IEFqYXhRdWV1ZSgpO1xuXG4gICAgICAgIF8uZWFjaChpZHMsIGZ1bmN0aW9uICh1c2VySWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyID0gdGhpcy51c2Vycy5nZXRCeUlkKHVzZXJJZCk7XG4gICAgICAgICAgICB1c2VyLnNldCgnd29ybGQnLCAnJyk7XG4gICAgICAgICAgICB1c2VyLnNldCgncm9sZScsICcnKTtcbiAgICAgICAgICAgIHF1ZXVlLmFkZChfLnBhcnRpYWwoXy5iaW5kKHRoaXMud29ybGRzLnVwZGF0ZVVzZXIsIHRoaXMud29ybGRzKSwgdXNlcikpO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIHVzYXNzaWduU2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICB2YXIgaWRzID0gdGhpcy5nZXRTZWxlY3RlZElkcygpO1xuXG4gICAgICAgIHZhciBkb25lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy53b3JsZHMuZmV0Y2goKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9oaWRlVXBkYXRpbmcoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudW5hc3NpZ25Vc2VycyhpZHMpLnRoZW4oZG9uZSk7XG4gICAgfSxcblxuICAgIG1ha2VVc2VySW5hY3RpdmU6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdmFyIGlkcyA9IHRoaXMuZ2V0U2VsZWN0ZWRJZHMoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIG1ha2VVc2Vyc0luYWN0aXZlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJvd3MgPSB0aGlzLmZpbmRSb3dWaWV3cyhpZHMpO1xuICAgICAgICAgICAgLy8gZm9yIG5vdyB3ZSBuZWVkIHRvIHNlcXVlbmNlIHRoZSBjYWxscyB0byBwYXRjaCB0aGUgdXNlcnNcbiAgICAgICAgICAgIC8vIHNpbmNlIHRoZSBBUEkgY2FuIG9ubHkgb3BlcmF0ZSBvbiBvbmUgY2FsbCBwZXIgZ3JvdXAgYXQgYSB0aW1lXG4gICAgICAgICAgICB2YXIgcXVldWUgPSBuZXcgQWpheFF1ZXVlKCk7XG4gICAgICAgICAgICBfLmVhY2gocm93cywgZnVuY3Rpb24gKHZpZXcpIHtcbiAgICAgICAgICAgICAgICB2YXIgdXNlciA9IHZpZXcubW9kZWw7XG4gICAgICAgICAgICAgICAgcXVldWUuYWRkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZpZXcubWFrZUluYWN0aXZlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZXcucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gdGhpcy51bmFzc2lnblVzZXJzKGlkcylcbiAgICAgICAgICAgIC50aGVuKG1ha2VVc2Vyc0luYWN0aXZlKTtcblxuXG4gICAgfSxcblxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiQoJ3RhYmxlIHRib2R5JykuZW1wdHkoKTtcbiAgICAgICAgdGhpcy5yZW5kZXJUYWJsZSgpO1xuICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgIH0sXG5cbiAgICByZW5kZXJUYWJsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJvd1ZpZXdzID0ge307XG4gICAgICAgIHZhciByb3dzID0gW107XG4gICAgICAgIHRoaXMudXNlcnMuZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgQXNzaWduZW1udFJvdyh7IG1vZGVsOiB1LCB3b3JsZHM6IHRoaXMud29ybGRzLCBwcm9qZWN0OiB0aGlzLnByb2plY3QgfSk7XG4gICAgICAgICAgICB0aGlzLnJvd1ZpZXdzW3UuZ2V0KCdpZCcpXSA9IHZpZXc7XG4gICAgICAgICAgICByb3dzLnB1c2godmlldy5yZW5kZXIoKS5lbCk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHRoaXMuJCgndGFibGUgdGJvZHknKS5hcHBlbmQocm93cyk7XG4gICAgfSxcblxuXG4gICAgdXBkYXRlQ29udHJvbHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9sc0ZvclNlbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnVwZGF0ZUF1dG9Bc3NpZ25CdXR0b24oKTtcbiAgICAgICAgdGhpcy51cGRhdGVTdGF0dXMoKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlU3RhdHVzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbmNvbHBsZXRlV29ybGRzID0gdGhpcy53b3JsZHMuZ2V0SW5jb21wbGV0ZVdvcmxkc0NvdW50KCk7XG4gICAgICAgIHZhciB1bmFzc2lnbmVkVXNlcnMgPSB0aGlzLnVzZXJzLmdldFVuYXNzaWduZWRVc2Vyc0NvdW50KCk7XG4gICAgICAgIHZhciB0b3RhbFdvcmxkcyA9IHRoaXMud29ybGRzLnNpemUoKTtcblxuICAgICAgICB2YXIgdXNlcnNUZXh0ID0gdW5hc3NpZ25lZFVzZXJzID8gdW5hc3NpZ25lZFVzZXJzID09PSAxID8gJzEgdXNlciBuZWVkcyBhc3NpZ25tZW50LicgOiB1bmFzc2lnbmVkVXNlcnMgKyAnIHVzZXJzIG5lZWQgYXNzaWdubWVudC4nIDogJ0FsbCB1c2VycyBoYXZlIGJlZW4gYXNzaWduZWQuJztcbiAgICAgICAgdmFyIHdvcmxkc1RleHQgPSAhdG90YWxXb3JsZHMgPyAnTm8gd29ybGRzIGhhdmUgYmVlbiBjcmVhdGVkLicgOiAhaW5jb2xwbGV0ZVdvcmxkcyA/ICdBbGwgd29ybGRzIGFyZSBjb21wbGV0ZS4nIDogaW5jb2xwbGV0ZVdvcmxkcyA9PT0gMSA/ICcxIGluY29tcGxldGUgd29ybGQgbmVlZHMgYXR0ZW50aW9uLicgOiBpbmNvbHBsZXRlV29ybGRzICsgJyBpbmNvbXBsZXRlIHdvcmxkcyBuZWVkIGF0dGVudGlvbi4nO1xuXG4gICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cyAudGV4dCcpLnRleHQodXNlcnNUZXh0KTtcbiAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cyAudGV4dCcpLnRleHQod29ybGRzVGV4dCk7XG5cbiAgICAgICAgaWYgKHVuYXNzaWduZWRVc2Vycykge1xuICAgICAgICAgICAgdGhpcy4kKCcjdXNlcnMtc3RhdHVzJykuYWRkQ2xhc3MoJ2luY29tcGxldGUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5jb2xwbGV0ZVdvcmxkcyB8fCAhdG90YWxXb3JsZHMpIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3dvcmxkcy1zdGF0dXMnKS5hZGRDbGFzcygnaW5jb21wbGV0ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLiQoJy5zdGF0dXMtd2lkZ2V0JykuYWRkQ2xhc3MoJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQ29udHJvbHNGb3JTZWxlY3Rpb246IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG51bVNlbGVjdGVkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpLmxlbmd0aDtcbiAgICAgICAgdGhpcy4kKCcuY29tcG9uZW50LmNvbnRyb2xzJylbbnVtU2VsZWN0ZWQgPyAnYWRkQ2xhc3MnIDogJ3JlbW92ZUNsYXNzJ10oJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQXV0b0Fzc2lnbkJ1dHRvbjogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIGlmICh0aGlzLnByb2plY3QuaXNEeW5hbWljQXNzaWdubWVudCgpKSB7XG4gICAgICAgICAgICB2YXIgaGFzUm9sZXMgPSB0aGlzLnByb2plY3QuaGFzUm9sZXMoKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5zaW5nbGUnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYycpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5keW5hbWljLW5vLXJvbGVzLXRleHQnKVtoYXNSb2xlcyA/ICdoaWRlJyA6ICdzaG93J10oKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpW2hhc1JvbGVzID8gJ2hpZGUnIDogJ3Nob3cnXSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLmR5bmFtaWMnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYy1uby1yb2xlcy10ZXh0JykuaGlkZSgpO1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLnNpbmdsZScpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpLnNob3coKTtcblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudXNlcnMuYWxsVXNlcnNBc3NpZ25lZCgpKSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLnJlbW92ZUNsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLmFkZENsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc2VsZWN0QWxsOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICB0aGlzLiQoJ3Rib2R5IDpjaGVja2JveCcpLnByb3AoJ2NoZWNrZWQnLCBlLnRhcmdldC5jaGVja2VkKTtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICB0b2dnbGVDb250cm9sbHM6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB0b3RhbCA9IHRoaXMuJCgndGJvZHkgOmNoZWNrYm94Jyk7XG4gICAgICAgIHZhciBjaGVja2VkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpO1xuXG4gICAgICAgIGlmICh0b3RhbC5sZW5ndGggPT09IGNoZWNrZWQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykuYXR0cignY2hlY2tlZCcsICdjaGVja2VkJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykucmVtb3ZlQXR0cignY2hlY2tlZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICBfc2hvd1VwZGF0aW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLmNzcyh7IG9wYWNpdHk6IDAuNCB9KTtcbiAgICB9LFxuXG4gICAgX2hpZGVVcGRhdGluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5jc3MoeyBvcGFjaXR5OiAxIH0pO1xuICAgIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBc3NpZ25tZW50OyIsIid1c2Ugc3RyaWN0JztcblxudmFyIEJhc2VDb2xsZWN0aW9uID0gZnVuY3Rpb24gKG1vZGVscywgb3B0aW9ucykge1xuICAgIHRoaXMuX21vZGVscyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlQ29sbGVjdGlvbi5wcm90b3R5cGUsIHtcbiAgICBpZEF0dHJpYnV0ZTogJ2lkJyxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uIChtb2RlbHMsIG9wdGlvbnMpIHtcbiAgICB9LFxuXG4gICAgY3JlYXRlOiBmdW5jdGlvbiAoYXR0ciwgb3B0aW9ucykge1xuICAgICAgICB2YXIgbSA9IG5ldyB0aGlzLm1vZGVsKGF0dHIsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnNldChtKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAobW9kZWxzLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMuX21vZGVscy5sZW5ndGggPSAwO1xuICAgICAgICB0aGlzLnNldChtb2RlbHMpO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uIChtb2RlbCkge1xuICAgICAgICBfLnJlbW92ZSh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbSA9PT0gbW9kZWw7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGRlbGV0ZSBtb2RlbC5jb2xsZWN0aW9uO1xuXG4gICAgICAgIHJldHVybiBtb2RlbDtcbiAgICB9LFxuXG4gICAgc2V0OiBmdW5jdGlvbiAobW9kZWxzKSB7XG4gICAgICAgIGlmICghbW9kZWxzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBtb2RlbHMgPSBbXS5jb25jYXQobW9kZWxzKTtcblxuICAgICAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIF8uZWFjaChtb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICBpZiAoIShtIGluc3RhbmNlb2YgdGhpcy5tb2RlbCkpIHtcbiAgICAgICAgICAgICAgICBtID0gbmV3IHRoaXMubW9kZWwobSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG0uY29sbGVjdGlvbiA9IHRoaXM7XG5cbiAgICAgICAgICAgIHRoaXMuX21vZGVscy5wdXNoKG0pO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICB0aGlzLnNvcnQuY2FsbCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gbW9kZWxzO1xuICAgIH0sXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBiLl9kYXRhW3RoaXMuaWRBdHRyaWJ1dGVdIC0gYS5fZGF0YVt0aGlzLmlkQXR0cmlidXRlXTtcbiAgICB9LFxuXG4gICAgc29ydDogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLl9tb2RlbHMgPSB0aGlzLl9tb2RlbHMuc29ydCh0aGlzLnNvcnRGbi5iaW5kKHRoaXMpKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzO1xuICAgIH0sXG5cbiAgICBnZXRCeUlkOiBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgcmV0dXJuIF8uZmluZCh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbS5nZXQodGhpcy5pZEF0dHJpYnV0ZSkgPT09IGlkO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgZWFjaDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uZWFjaCh0aGlzLl9tb2RlbHMsIGNiLCBjdHggfHwgdGhpcyk7XG4gICAgfSxcblxuICAgIGFsbDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uYWxsKHRoaXMuX21vZGVscywgY2IsIGN0eCB8fCB0aGlzKTtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBfLmludm9rZSh0aGlzLl9tb2RlbHMsICd0b0pTT04nKTtcbiAgICB9LFxuXG4gICAgZmluZDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbmQodGhpcy5fbW9kZWxzLCBmbik7XG4gICAgfSxcblxuICAgIGZpbHRlcjogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbHRlcih0aGlzLl9tb2RlbHMsIGZuKTtcbiAgICB9LFxuXG4gICAgc2l6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgbWFwOiBmdW5jdGlvbiAoZm4sIGN0eCkge1xuICAgICAgICByZXR1cm4gXy5tYXAodGhpcy5fbW9kZWxzLCBmdW5jdGlvbiAobW9kZWwpIHtcbiAgICAgICAgICAgIHJldHVybiBmbi5jYWxsKGN0eCwgbW9kZWwudG9KU09OKCkpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgcGx1Y2s6IGZ1bmN0aW9uIChmaWVsZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBtW2ZpZWxkXTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlQ29sbGVjdGlvbjsiLCIndXNlIHN0cmljdCc7XG5cblxudmFyIEJhc2VNb2RlbCA9IGZ1bmN0aW9uIChhdHRyLCBvcHRpb25zKSB7XG4gICAgYXR0ciA9IF8uZGVmYXVsdHMoe30sIGF0dHIsIF8ucmVzdWx0KHRoaXMsICdkZWZhdWx0cycpKTtcbiAgICB0aGlzLl9kYXRhID0ge307XG4gICAgdGhpcy5zZXQoYXR0ciwgb3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlTW9kZWwucHJvdG90eXBlLCB7XG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKGF0dHIsIG9wdGlvbnMpIHtcblxuICAgIH0sXG5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbCwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChrZXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWw7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBfLmV4dGVuZCh0aGlzLl9kYXRhLCBhdHRycyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGdldDogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YVtrZXldO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jb2xsZWN0aW9uLnJlbW92ZSh0aGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICB0b0pTT046IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGE7XG4gICAgfSxcblxuICAgIHBpY2s6IGZ1bmN0aW9uIChrZXlzKSB7XG4gICAgICAgIHJldHVybiBfLnBpY2sodGhpcy5fZGF0YSwga2V5cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlTW9kZWw7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZW52ID0ge1xuICAgIGFjY291bnQ6ICcnLFxuICAgIHByb2plY3Q6ICcnLFxuICAgIGdyb3VwOiAnJyxcbiAgICBncm91cElkOiAnJyxcbiAgICB0b2tlbjogJycsXG4gICAgc2VydmVyOiB7XG4gICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgcHJvdG9jb2w6ICdodHRwcydcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBzZXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGVudiA9IF8ubWVyZ2UoZW52LCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBlbnY7XG4gICAgfVxufTsiLCIoZnVuY3Rpb24gKCkge1xuICAgICd1c2Ugc3RyaWN0JztcbiAgICB2YXIgQXBwID0gcmVxdWlyZSgnLi9hc3NpZ25tZW50LmpzJyk7XG5cbiAgICB3aW5kb3cuZm9yaW8gPSB3aW5kb3cuZm9yaW8gfHwge307XG4gICAgd2luZG93LmZvcmlvLk11bHRpcGxheWVyQXNzaWdubWVudENvbXBvbmVudCA9IEFwcDtcbn0pKCk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBzZXJ2aWNlTG9jYXRvciA9IHJlcXVpcmUoJy4vc2VydmljZS1sb2NhdG9yJyk7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG4vLyB2YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBpc0R5bmFtaWNBc3NpZ25tZW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldCgnd29ybGRzJykgPT09ICdkeW5hbWljJztcbiAgICB9LFxuXG4gICAgaGFzUm9sZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJvbGVzID0gdGhpcy5nZXQoJ3JvbGVzJyk7XG4gICAgICAgIHJldHVybiByb2xlcyAmJiAhIXJvbGVzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGFwaSA9IHNlcnZpY2VMb2NhdG9yLndvcmxkQXBpKCk7XG5cbiAgICAgICAgcmV0dXJuIGFwaS5nZXRQcm9qZWN0U2V0dGluZ3MoKS50aGVuKGZ1bmN0aW9uIChzZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5zZXQoc2V0dGluZ3MpO1xuICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cbn0pOyIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVudiA9IHJlcXVpcmUoJy4vZGVmYXVsdHMuanMnKTtcblxudmFyIGNhY2hlID0ge307XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHdvcmxkQXBpOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghY2FjaGUud29ybGRBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLndvcmxkQXBpID0gbmV3IEYuc2VydmljZS5Xb3JsZChlbnYuZ2V0KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLndvcmxkQXBpO1xuICAgIH0sXG5cbiAgICBtZW1iZXJBcGk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFjYWNoZS5tZW1iZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLm1lbWJlckFwaSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKF8ucGljayhlbnYuZ2V0KCksIFsnZ3JvdXBJZCcsICdzZXJ2ZXInXSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLm1lbWJlckFwaTtcbiAgICB9LFxuXG4gICAgdXNlckFwaTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIWNhY2hlLnVzZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLnVzZXJBcGkgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoXy5waWNrKGVudi5nZXQoKSwgWydhY2NvdW50JywgJ3NlcnZlciddKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2FjaGUudXNlckFwaTtcbiAgICB9XG59OyIsImV4cG9ydHNbXCJlZGl0LXVzZXItcm93XCJdID0gZnVuY3Rpb24ob2JqKSB7XG5vYmogfHwgKG9iaiA9IHt9KTtcbnZhciBfX3QsIF9fcCA9ICcnLCBfX2UgPSBfLmVzY2FwZSwgX19qID0gQXJyYXkucHJvdG90eXBlLmpvaW47XG5mdW5jdGlvbiBwcmludCgpIHsgX19wICs9IF9fai5jYWxsKGFyZ3VtZW50cywgJycpIH1cbndpdGggKG9iaikge1xuX19wICs9ICc8dGQ+PGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGNsYXNzPVwic2VsZWN0XCIgZGF0YS1pZD1cIicgK1xuKChfX3QgPSAoIGlkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+PC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cIndvcmxkc1wiIGNsYXNzPVwiZm9ybS1jb250cm9sXCIgZGF0YS1maWVsZD1cIndvcmxkXCI+XFxuXFxuICAgICc7XG4gXy5lYWNoKHdvcmxkcywgZnVuY3Rpb24gKHcpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHcgPT09IHdvcmxkID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIicgK1xuKChfX3QgPSAoIG5ld1dvcmxkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiIGNsYXNzPVwibmV3LXdvcmxkLXRleHRcIj48aT4nICtcbigoX190ID0gKCBuZXdXb3JsZCApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbicgLSBOZXcgLTwvaT48L29wdGlvbj5cXG4gICAgPC9zZWxlY3Q+XFxuPC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cInJvbGVzXCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBkYXRhLWZpZWxkPVwicm9sZVwiPlxcbiAgICAnO1xuIF8uZWFjaChyb2xlcywgZnVuY3Rpb24gKHIpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHIgPT09IHJvbGUgPyAnc2VsZWN0ZWQnIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPicgK1xuKChfX3QgPSAoIHIgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC9vcHRpb24+XFxuICAgICc7XG4gfSk7IDtcbl9fcCArPSAnXFxuXFxuICAgICc7XG4gXy5lYWNoKG9wdGlvbmFsUm9sZXMsIGZ1bmN0aW9uIChyKSB7IDtcbl9fcCArPSAnXFxuICAgICAgICA8b3B0aW9uIHZhbHVlPVwiJyArXG4oKF9fdCA9ICggciApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbidcIiAnICtcbigoX190ID0gKCByID09PSByb2xlID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJyA8aT4oT3B0aW9uYWwpPC9pPjwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICA8L3NlbGVjdD5cXG48L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi10b29scyBidG4tc2F2ZSBzYXZlXCI+U2F2ZTwvYnV0dG9uPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi10b29scyBidG4tY2FuY2VsIGNhbmNlbFwiPkNhbmNlbDwvYnV0dG9uPlxcbjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTtcbmV4cG9ydHNbXCJ1c2VyLXJvd1wiXSA9IGZ1bmN0aW9uKG9iaikge1xub2JqIHx8IChvYmogPSB7fSk7XG52YXIgX190LCBfX3AgPSAnJywgX19lID0gXy5lc2NhcGU7XG53aXRoIChvYmopIHtcbl9fcCArPSAnPHRkPjxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cInNlbGVjdFwiIGRhdGEtaWQ9XCInICtcbigoX190ID0gKCBpZCkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggIWlzV29ybGRDb21wbGV0ZSA/ICc8ZW0gY2xhc3M9XCJmLWljb24gZi13YXJuaW5nXCI+PC9lbT4nIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggd29ybGQgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggcm9sZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPjxidXR0b24gY2xhc3M9XCJidG4gZWRpdCBidG4tZWRpdCBidG4tdG9vbHMgYXV0by1oaWRlXCI+RWRpdDwvYnV0dG9uPjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBkZWZhdWx0czoge1xuICAgICAgICB3b3JsZDogJycsXG4gICAgICAgIHJvbGU6ICcnLFxuICAgICAgICBhY3RpdmU6IHRydWUsXG4gICAgICAgIGlzV29ybGRDb21wbGV0ZTogdHJ1ZSxcbiAgICAgICAgZmlyc3ROYW1lOiAnJyxcbiAgICAgICAgbGFzdE5hbWU6ICcnXG4gICAgfSxcblxuICAgIG1ha2VBY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gbWVtYmVyQXBpLm1ha2VVc2VyQWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBtYWtlSW5hY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBmYWxzZSk7XG5cbiAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5tYWtlVXNlckluYWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cblxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcblxudmFyIE1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcblxuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBtb2RlbDogTW9kZWwsXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHZhciBhdyA9IGEuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBidyA9IGIuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIGlmIChhdyAhPT0gYncpIHtcbiAgICAgICAgICAgIHJldHVybiBhdyA8IGJ3ID8gLTEgOiAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGIuZ2V0KCd1c2VyTmFtZScpID4gYS5nZXQoJ3VzZXJOYW1lJykgPyAtMSA6IDE7XG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJC5hamF4U2V0dXAoe1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIGVudi5nZXQoKS50b2tlblxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgYWxsVXNlcnNBc3NpZ25lZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hbGwoZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiAhIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0VW5hc3NpZ25lZFVzZXJzQ291bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmlsdGVyKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICByZXR1cm4gIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KS5sZW5ndGg7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBncm91cElkID0gZW52LmdldCgpLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGdldEdyb3VwVXNlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbWVtYmVyQXBpID0gc2VydmljZUxvY2F0b3IubWVtYmVyQXBpKCk7XG4gICAgICAgICAgICB2YXIgdXNlckFwaSA9IHNlcnZpY2VMb2NhdG9yLnVzZXJBcGkoKTtcblxuICAgICAgICAgICAgdmFyIGxvYWRHcm91cE1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5nZXRHcm91cERldGFpbHMoKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBsb2FkVXNlcnNJbmZvID0gZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vbkZhY0FuZEFjdGl2ZSA9IGZ1bmN0aW9uICh1KSB7IHJldHVybiB1LmFjdGl2ZSAmJiB1LnJvbGUgIT09ICdmYWNpbGl0YXRvcic7IH07XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJzID0gXy5wbHVjayhfLmZpbHRlcihncm91cC5tZW1iZXJzLCBub25GYWNBbmRBY3RpdmUpLCAndXNlcklkJyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVzZXJBcGkuZ2V0KHsgaWQ6IHVzZXJzIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGxvYWRHcm91cE1lbWJlcnMoKVxuICAgICAgICAgICAgICAgIC50aGVuKGxvYWRVc2Vyc0luZm8pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgZ2V0R3JvdXBVc2VycygpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAodXNlcnMpIHtcbiAgICAgICAgICAgICAgICB1c2VycyA9IF8ubWFwKHVzZXJzLCBmdW5jdGlvbiAodSkgeyByZXR1cm4gXy5leHRlbmQodSwgeyBncm91cElkOiBncm91cElkIH0pOyB9KTtcbiAgICAgICAgICAgICAgICBfdGhpcy5zZXQodXNlcnMpO1xuICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHVzZXJzLCBfdGhpcyk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9XG5cbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBkZWZhdWx0czoge1xuICAgICAgICB1c2VyczogbnVsbCxcbiAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX19zdXBlci5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgdGhpcy5fZGF0YS51c2VycyA9IHRoaXMuX2RhdGEudXNlcnMgfHwgW107XG5cbiAgICAgICAgdGhpcy5fd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuXG4gICAgICAgIHZhciBpZCA9IHRoaXMuZ2V0KCdpZCcpO1xuICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgYWRkVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIHVzZXJzLnB1c2godXNlcik7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuc2F2ZSgpO1xuICAgIH0sXG5cbiAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlcikge1xuICAgICAgICB2YXIgaWQgPSB0aGlzLmdldCgnaWQnKTtcbiAgICAgICAgdmFyIGNoZWNrV29ybGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuZ2V0KCd1c2VycycpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSkuZGVsZXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICBfLnJlbW92ZSh0aGlzLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiB1LmdldCgnaWQnKSA9PT0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl93b3JsZEFwaVxuICAgICAgICAgICAgLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSlcbiAgICAgICAgICAgIC5yZW1vdmVVc2VyKHsgdXNlcklkOiB1c2VyLmdldCgnaWQnKSB9KVxuICAgICAgICAgICAgLnRoZW4oY2hlY2tXb3JsZCk7XG4gICAgfSxcblxuICAgIHNhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIG1hcFVzZXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIF8ubWFwKHRoaXMuZ2V0KCd1c2VycycpLCBmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgICAgIHZhciByZXMgPSB7IHVzZXJJZDogdS5nZXQoJ2lkJykgfTtcbiAgICAgICAgICAgICAgICB2YXIgcm9sZSA9IHUuZ2V0KCdyb2xlJyk7XG5cbiAgICAgICAgICAgICAgICBpZiAocm9sZSkge1xuICAgICAgICAgICAgICAgICAgICByZXMucm9sZSA9IHJvbGU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIGNyZWF0ZVdvcmxkID0gXy5wYXJ0aWFsKHRoaXMuX3dvcmxkQXBpLmNyZWF0ZSwgdGhpcy5waWNrKFsnbW9kZWwnLCAnbmFtZScsICdtaW5Vc2VycyddKSk7XG4gICAgICAgIHZhciBhZGRVc2VycyA9IF8ucGFydGlhbChfdGhpcy5fd29ybGRBcGkuYWRkVXNlcnMsIG1hcFVzZXJzKCksIHsgZmlsdGVyOiBfdGhpcy5nZXQoJ2lkJykgfSk7XG4gICAgICAgIHZhciBzYXZlZFVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIGlmICh0aGlzLmlzTmV3KCkpIHtcbiAgICAgICAgICAgIC8vIHdlIG5lZWQgdG8gY3JlYXRlIHRoZSB3b3JsZCBpbiB0aGUgQVBJIGFuZCB0aGVuIGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVXb3JsZCgpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNldCh3b3JsZCk7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLl93b3JsZEFwaS51cGRhdGVDb25maWcoeyBmaWx0ZXI6IHdvcmxkLmlkIH0pO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oYWRkVXNlcnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHVzZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHNpbmNlIHdlIHJlLXNldCB0aGUgd29ybGQsIHJlLXNldCB0aGUgdXNlcnNcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuc2V0KCd1c2VycycsIHNhdmVkVXNlcnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gdGhlIHdvcmxkIGlzIGFscmVhZHkgY3JlYXRlZCBqdXN0IGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBhZGRVc2VycygpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGlzTmV3OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5nZXQoJ2xhc3RNb2RpZmllZCcpO1xuICAgIH1cblxufSk7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgTW9kZWwgPSByZXF1aXJlKCcuL3dvcmxkLW1vZGVsJyk7XG52YXIgVXNlck1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG52YXIgZG9uZUZuID0gZnVuY3Rpb24gKGR0ZCwgYWZ0ZXIpIHtcbiAgICByZXR1cm4gXy5hZnRlcihhZnRlciwgZHRkLnJlc29sdmUpO1xufTtcblxudmFyIHdvcmxkQXBpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgbW9kZWw6IE1vZGVsLFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBfX3N1cGVyLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuICAgIH0sXG5cbiAgICBhdXRvQXNzaWduQWxsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gd29ybGRBcGkuYXV0b0Fzc2lnbihvcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzZXQodGhpcy5wYXJzZSh3b3JsZHMpKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGdldEluY29tcGxldGVXb3JsZHNDb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24gKHcpIHtcbiAgICAgICAgICAgIHJldHVybiAhdy5nZXQoJ2NvbXBsZXRlJyk7XG4gICAgICAgIH0pLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgdXBkYXRlVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHdvcmxkTmFtZSA9IHVzZXIuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgcHJldldvcmxkID0gdGhpcy5nZXRXb3JsZEJ5VXNlcih1c2VyKTtcbiAgICAgICAgdmFyIGN1cldvcmxkID0gdGhpcy5nZXRPckNyZWF0ZVdvcmxkKHdvcmxkTmFtZSk7XG4gICAgICAgIHZhciBkb25lID0gZG9uZUZuKGR0ZCwgMSk7XG5cbiAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUncyBhbnl0aGluZyB0byBkb1xuICAgICAgICBpZiAoIXByZXZXb3JsZCAmJiAhY3VyV29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiBkdGQucmVzb2x2ZSgpLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwcmV2V29ybGQpIHtcbiAgICAgICAgICAgIHByZXZXb3JsZC5yZW1vdmVVc2VyKHVzZXIpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY3VyV29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjdXJXb3JsZC5hZGRVc2VyKHVzZXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAudGhlbihkb25lKTtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJXb3JsZCkge1xuICAgICAgICAgICAgY3VyV29ybGQuYWRkVXNlcih1c2VyKVxuICAgICAgICAgICAgICAgIC50aGVuKGRvbmUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldE9yQ3JlYXRlV29ybGQ6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgaWYgKCF3b3JsZE5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB3b3JsZCA9IHRoaXMuZ2V0V29yZEJ5TmFtZSh3b3JsZE5hbWUpO1xuXG4gICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgIHdvcmxkID0gdGhpcy5jcmVhdGUoeyBuYW1lOiB3b3JsZE5hbWUgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gd29ybGQ7XG4gICAgfSxcblxuICAgIGdldFdvcmRCeU5hbWU6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmluZChmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiB3b3JsZC5nZXQoJ25hbWUnKSA9PT0gd29ybGROYW1lO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGRCeVVzZXI6IGZ1bmN0aW9uICh1c2VyKSB7XG4gICAgICAgIGlmICghdXNlci5nZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZ2V0V29ybGRCeVVzZXIgZXhwZWN0ZXMgYSBtb2RlbCAoJyArIHVzZXIgKyAnKScpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGlkID0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFdvcmxkQnlVc2VySWQoaWQpO1xuICAgIH0sXG5cbiAgICBnZXRXb3JsZEJ5VXNlcklkOiBmdW5jdGlvbiAodXNlcklkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZpbmQoZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICByZXR1cm4gXy5maW5kKHdvcmxkLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdS5nZXQoJ2lkJykgPT09IHVzZXJJZDtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGROYW1lczogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wbHVjaygnbmFtZScpO1xuICAgIH0sXG5cbiAgICBnZXROZXh0V29ybGROYW1lOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBwYWQgPSBmdW5jdGlvbiAobnVtLCBwbGFjZXMpIHtcbiAgICAgICAgICAgIHZhciB6ZXJvcyA9ICcwMDAwMDAwMDAwMDAwMDAwMDAnO1xuICAgICAgICAgICAgdmFyIGRpZ2l0cyA9IG51bS50b1N0cmluZygpLmxlbmd0aDtcbiAgICAgICAgICAgIHZhciBuZWVkZWQgPSBwbGFjZXMgLSBkaWdpdHM7XG4gICAgICAgICAgICByZXR1cm4gemVyb3Muc3Vic3RyKDAsIG5lZWRlZCkgKyBudW07XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHdvcmxkcyA9IHRoaXMuZ2V0V29ybGROYW1lcygpO1xuXG4gICAgICAgIGlmICghd29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuICdXb3JsZDAwMSc7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcHJvcGVyTmFtZXMgPSBfLmZpbHRlcih3b3JsZHMsIGZ1bmN0aW9uICh3KSB7IHJldHVybiAvV29ybGRcXGRcXGRcXGQvLnRlc3Qodyk7IH0pLnNvcnQoKTtcbiAgICAgICAgdmFyIGxhc3RXb3JsZCA9IHByb3Blck5hbWVzW3Byb3Blck5hbWVzLmxlbmd0aCAtIDFdO1xuICAgICAgICB2YXIgbnVtV29ybGQgPSArbGFzdFdvcmxkLm1hdGNoKC9Xb3JsZChcXGRcXGRcXGQpLylbMV07XG4gICAgICAgIHJldHVybiAnV29ybGQnICsgcGFkKG51bVdvcmxkICsgMSwgMyk7XG4gICAgfSxcblxuICAgIHNldFVzZXJzQ29sbGVjdGlvbjogZnVuY3Rpb24gKHVzZXJzQ29sbGVjdGlvbikge1xuICAgICAgICB0aGlzLnVzZXJzQ29sbGVjdGlvbiA9IHVzZXJzQ29sbGVjdGlvbjtcbiAgICB9LFxuXG4gICAgam9pblVzZXJzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1c2Vyc0hhc2ggPSB7fTtcbiAgICAgICAgdmFyIHVzZXJzQ29sbGVjdGlvbiA9IHRoaXMudXNlcnNDb2xsZWN0aW9uO1xuICAgICAgICB1c2Vyc0NvbGxlY3Rpb24uZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdS5zZXQoeyBpc1dvcmxkQ29tcGxldGU6IHRydWUgfSk7XG4gICAgICAgICAgICByZXR1cm4gKHVzZXJzSGFzaFt1LmdldCgnaWQnKV0gPSB1KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5lYWNoKGZ1bmN0aW9uICh3LCBpKSB7XG4gICAgICAgICAgICB2YXIgbmFtZSA9IHcuZ2V0KCduYW1lJyk7XG4gICAgICAgICAgICB2YXIgaXNDb21wbGV0ZSA9IHcuZ2V0KCdjb21wbGV0ZScpO1xuICAgICAgICAgICAgdy5zZXQoeyBpbmRleDogaSwgbmFtZTogbmFtZSB8fCAoaSArIDEpICsgJycgfSk7XG4gICAgICAgICAgICBfLmVhY2gody5nZXQoJ3VzZXJzJyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgaWYgKHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldKSB7XG4gICAgICAgICAgICAgICAgICAgIHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldLnNldCh7IHdvcmxkOiBuYW1lLCByb2xlOiB1LmdldCgncm9sZScpLCBpc1dvcmxkQ29tcGxldGU6IGlzQ29tcGxldGUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHVzZXJzQ29sbGVjdGlvbi5zb3J0KCk7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB3b3JsZEFwaS5saXN0KClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc2V0KHRoaXMucGFyc2Uod29ybGRzKSk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBwYXJzZTogZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICBpZiAod29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgd29ybGRzID0gXy5tYXAod29ybGRzLCBmdW5jdGlvbiAodykge1xuICAgICAgICAgICAgICAgIHZhciB1c2VycyA9IF8ubWFwKHcudXNlcnMsIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGluIHRoZSB3b3JsZCBhcGkgdXNlcnMgSWRzIGNvbWVzIGFzIHVzZXJJZFxuICAgICAgICAgICAgICAgICAgICAvLyBtYWtlIHN1cmUgd2UgYWRkIGl0IGFzIGlkIHNvIHdlIGNhbiB1c2UgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIHNhbWUgY29kZSB0byBhY2Nlc3MgbW9kZWxzIHRoYXQgY29tZSBmcm9tIHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyBtZW1iZXIvbG9jYWwgYXBpIGFzIHdpdGggdGhlIHdvcmxkIGFwaVxuICAgICAgICAgICAgICAgICAgICB1LmlkID0gdS51c2VySWQ7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVXNlck1vZGVsKHUpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgdy51c2VycyA9IHVzZXJzO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHc7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB3b3JsZHM7XG4gICAgfVxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuKiBVdGlsaXR5IGNsYXNzIHRvIG1ha2UgYWpheCBjYWxscyBzZXF1ZW5jaWFsXG4qL1xuZnVuY3Rpb24gQWpheFF1ZXVlICgpIHtcbiAgICB0aGlzLnF1ZXVlID0gW107XG59XG5cbiQuZXh0ZW5kKEFqYXhRdWV1ZS5wcm90b3R5cGUsIHtcbiAgICBhZGQ6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICByZXR1cm4gdGhpcy5xdWV1ZS5wdXNoKGZuKTtcbiAgICB9LFxuXG4gICAgZXhlY3V0ZTogZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgY29udGV4dCA9IGNvbnRleHQgfHwgdGhpcztcblxuICAgICAgICBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgICAgICAgaWYgKF90aGlzLnF1ZXVlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBmbiA9IF90aGlzLnF1ZXVlLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgICAgICBmbi5jYWxsKGNvbnRleHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKG5leHQpXG4gICAgICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbmV4dCgpO1xuXG4gICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQWpheFF1ZXVlOyIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiJdfQ== +//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Fzc2lnbm1lbnQtcm93LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9hc3NpZ25tZW50LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9iYXNlLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Jhc2UtbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2RlZmF1bHRzLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9pbmRleC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvcHJvamVjdC1tb2RlbC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvc2VydmljZS1sb2NhdG9yLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy90ZW1wbGF0ZXMuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXItbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXJzLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3dvcmxkLW1vZGVsLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy93b3JsZHMtY29sbGVjdGlvbi5qcyIsInNyYy91dGlsL2FqYXgtcXVldWUuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCc7XG5cbnZhciB0ZW1wbGF0ZXMgPSByZXF1aXJlKCcuL3RlbXBsYXRlcycpO1xuXG52YXIgQXNzaWdubWVudFJvdyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy4kZWwgPSAkKCc8dHI+Jyk7XG4gICAgdGhpcy5lbCA9IHRoaXMuJGVsWzBdO1xuICAgIHRoaXMuJCA9IF8ucGFydGlhbFJpZ2h0KCQsIHRoaXMuJGVsKTtcblxuICAgIHRoaXMubW9kZWwgPSBvcHRpb25zLm1vZGVsO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy53b3JsZHMgPSBvcHRpb25zLndvcmxkcztcbiAgICB0aGlzLnByb2plY3QgPSBvcHRpb25zLnByb2plY3Q7XG5cbiAgICBfLmJpbmRBbGwodGhpcywgWydzZXRFZGl0TW9kZScsICdyZW1vdmVFZGl0TW9kZScsICdzYXZlRWRpdCcsICdjYW5jZWxFZGl0JywgJ3VwZGF0ZURhdGEnXSk7XG5cbiAgICB0aGlzLmJpbmRFdmVudHMoKTtcblxufTtcblxuXy5leHRlbmQoQXNzaWdubWVudFJvdy5wcm90b3R5cGUsIHtcblxuICAgIHRlbXBsYXRlOiB0ZW1wbGF0ZXNbJ3VzZXItcm93J10sXG5cbiAgICBlZGl0VGVtcGxhdGU6IHRlbXBsYXRlc1snZWRpdC11c2VyLXJvdyddLFxuXG4gICAgYmluZEV2ZW50czogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnYnV0dG9uLmVkaXQnLCB0aGlzLnNldEVkaXRNb2RlKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2J1dHRvbi5zYXZlJywgdGhpcy5zYXZlRWRpdCk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICdidXR0b24uY2FuY2VsJywgdGhpcy5jYW5jZWxFZGl0KTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9mZignY2xpY2snLCBudWxsLCBudWxsKTtcbiAgICAgICAgLy8gdGhpcyBvbmx5IGdpdmVzIGEgZGVsYXkgdG8gcmVtb3ZlIHRoZSB0clxuICAgICAgICAvLyBhbmltYXRpb24gb2YgaGVpZ2h0IG9mIHRoZSB0ciBkb2VzIG5vdCB3b3JrXG4gICAgICAgIHRoaXMuJCgnOmNoZWNrYm94JykuYXR0cignY2hlY2tlZCcsIGZhbHNlKTtcbiAgICAgICAgdGhpcy4kZWxcbiAgICAgICAgICAgIC5jc3MoeyBvcGFjaXR5OiAwLjMgfSlcbiAgICAgICAgICAgIC5hbmltYXRlKHsgaGVpZ2h0OiAwIH0sIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMzAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIG1ha2VJbmFjdGl2ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tb2RlbC5tYWtlSW5hY3RpdmUoKTtcbiAgICB9LFxuXG4gICAgc2V0RWRpdE1vZGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5tb2RlbC5zZXQoJ2VkaXQtbW9kZScsIHRydWUpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICByZW1vdmVFZGl0TW9kZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLm1vZGVsLnNldCgnZWRpdC1tb2RlJywgZmFsc2UpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICBzYXZlRWRpdDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB0aGlzLnVwZGF0ZURhdGEoKTtcbiAgICAgICAgdGhpcy53b3JsZHNcbiAgICAgICAgICAgIC51cGRhdGVVc2VyKHRoaXMubW9kZWwpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMucmVtb3ZlRWRpdE1vZGUoKTtcbiAgICAgICAgICAgICAgICBfdGhpcy4kZWwudHJpZ2dlcigndXBkYXRlJywgX3RoaXMpO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGNhbmNlbEVkaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVFZGl0TW9kZSgpO1xuICAgIH0sXG5cbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHRlbXBsID0gdGhpcy5tb2RlbC5nZXQoJ2VkaXQtbW9kZScpID8gdGhpcy5lZGl0VGVtcGxhdGUgOiB0aGlzLnRlbXBsYXRlO1xuICAgICAgICB2YXIgdm0gPSBfLmV4dGVuZCh7XG4gICAgICAgICAgICByb2xlczogdGhpcy5wcm9qZWN0LmdldCgncm9sZXMnKSxcbiAgICAgICAgICAgIG9wdGlvbmFsUm9sZXM6IHRoaXMucHJvamVjdC5nZXQoJ29wdGlvbmFsUm9sZXMnKSxcbiAgICAgICAgICAgIHdvcmxkczogdGhpcy53b3JsZHMuZ2V0V29ybGROYW1lcygpLFxuICAgICAgICAgICAgbmV3V29ybGQ6IHRoaXMud29ybGRzLmdldE5leHRXb3JsZE5hbWUoKVxuICAgICAgICB9LCB0aGlzLm1vZGVsLnRvSlNPTigpKTtcblxuICAgICAgICB0aGlzLiRlbC5odG1sKHRlbXBsKHZtKSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIHVwZGF0ZURhdGE6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdGhpcy4kKCdbZGF0YS1maWVsZF0nKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBlbCA9ICQodGhpcyk7XG4gICAgICAgICAgICB2YXIgZmllbGQgPSBlbC5kYXRhKCdmaWVsZCcpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IGVsLnZhbCgpO1xuXG4gICAgICAgICAgICBfdGhpcy5tb2RlbC5zZXQoZmllbGQsIHZhbCk7XG4gICAgICAgIH0pO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQXNzaWdubWVudFJvdzsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBVc2Vyc0NvbGxlY3Rpb24gPSByZXF1aXJlKCcuL3VzZXJzLWNvbGxlY3Rpb24nKTtcbnZhciBXb3JsZHNDb2xsZWN0aW9uID0gcmVxdWlyZSgnLi93b3JsZHMtY29sbGVjdGlvbicpO1xudmFyIFByb2plY3RNb2RlbCA9IHJlcXVpcmUoJy4vcHJvamVjdC1tb2RlbCcpO1xudmFyIEFzc2lnbmVtbnRSb3cgPSByZXF1aXJlKCcuL2Fzc2lnbm1lbnQtcm93Jyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIEFqYXhRdWV1ZSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvYWpheC1xdWV1ZScpO1xuXG5mdW5jdGlvbiBzZXRFbnZpcm9ubWVudChvcHRpb25zKSB7XG4gICAgZW52LnNldChfLm9taXQob3B0aW9ucywgJ2VsJykpO1xufVxuXG52YXIgQXNzaWdubWVudCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgc2V0RW52aXJvbm1lbnQob3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplKG9wdGlvbnMpO1xufTtcblxuQXNzaWdubWVudC5wcm90b3R5cGUgPSB7XG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLmVsID0gdHlwZW9mIG9wdGlvbnMuZWwgPT09ICdzdHJpbmcnID8gJChvcHRpb25zLmVsKVswXSA6IG9wdGlvbnMuZWw7XG4gICAgICAgIHRoaXMuJGVsID0gJCh0aGlzLmVsKTtcbiAgICAgICAgdGhpcy4kID0gXy5wYXJ0aWFsUmlnaHQoJCwgdGhpcy5lbCk7XG5cbiAgICAgICAgdGhpcy51c2VycyA9IG5ldyBVc2Vyc0NvbGxlY3Rpb24oKTtcbiAgICAgICAgdGhpcy53b3JsZHMgPSBuZXcgV29ybGRzQ29sbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnByb2plY3QgPSBuZXcgUHJvamVjdE1vZGVsKCk7XG5cbiAgICAgICAgXy5iaW5kQWxsKHRoaXMsIFsncmVuZGVyJywgJ3JlbmRlclRhYmxlJywgJ3RvZ2dsZUNvbnRyb2xscycsICdzYXZlRWRpdCcsICdzZWxlY3RBbGwnLCAndXNhc3NpZ25TZWxlY3RlZCcsICdfc2hvd1VwZGF0aW5nJywgJ19oaWRlVXBkYXRpbmcnLCAnYXV0b0Fzc2lnbkFsbCcsICdtYWtlVXNlckluYWN0aXZlJ10pO1xuXG4gICAgICAgIHRoaXMuYmluZEV2ZW50cygpO1xuICAgIH0sXG5cbiAgICBiaW5kRXZlbnRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9uKCd1cGRhdGUnLCAndHInLCB0aGlzLnNhdmVFZGl0KTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2lucHV0OmNoZWNrYm94Om5vdCgjc2VsZWN0LWFsbCknLCB0aGlzLnRvZ2dsZUNvbnRyb2xscyk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICcjc2VsZWN0LWFsbCcsIHRoaXMuc2VsZWN0QWxsKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy51bmFzc2lnbi11c2VyJywgdGhpcy51c2Fzc2lnblNlbGVjdGVkKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy5hdXRvLWFzc2lnbi1hbGwnLCB0aGlzLmF1dG9Bc3NpZ25BbGwpO1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnLm1ha2UtdXNlci1pbmFjdGl2ZScsIHRoaXMubWFrZVVzZXJJbmFjdGl2ZSk7XG4gICAgfSxcblxuICAgIGxvYWQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB2YXIgam9pbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLnNldFVzZXJzQ29sbGVjdGlvbih0aGlzLnVzZXJzKTtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLmpvaW5Vc2VycygpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHJldHVybiAkLndoZW4oXG4gICAgICAgICAgICB0aGlzLndvcmxkcy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy51c2Vycy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy5wcm9qZWN0LmZldGNoKClcbiAgICAgICAgKS50aGVuKGpvaW4pO1xuXG4gICAgfSxcblxuICAgIHNhdmVFZGl0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMud29ybGRzLmZldGNoKClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ29udHJvbHMoKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGF1dG9Bc3NpZ25BbGw6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG4gICAgICAgIHZhciBtYXhVc2VycyA9ICt0aGlzLiQoJyNtYXgtdXNlcnMnKS52YWwoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMud29ybGRzLmF1dG9Bc3NpZ25BbGwoeyBtYXhVc2VyczogbWF4VXNlcnMgfSlcbiAgICAgICAgICAgIC5kb25lKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC5mYWlsKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9LFxuXG4gICAgZ2V0U2VsZWN0ZWRJZHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuJCgndGJvZHkgOmNoZWNrYm94OmNoZWNrZWQnKS5tYXAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICQodGhpcykuZGF0YSgnaWQnKTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGZpbmRSb3dWaWV3czogZnVuY3Rpb24gKGlkcykge1xuICAgICAgICByZXR1cm4gXy5tYXAoaWRzLCBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJvd1ZpZXdzW2lkXTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfSxcblxuICAgIHVuYXNzaWduVXNlcnM6IGZ1bmN0aW9uIChpZHMpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIGZvciBub3cgd2UgbmVlZCB0byBzZXF1ZW5jZSB0aGUgY2FsbHMgdG8gdW5hc3NpZ24gdXNlcnMgZnJvbSB3b3JsZHNcbiAgICAgICAgdmFyIHF1ZXVlID0gbmV3IEFqYXhRdWV1ZSgpO1xuXG4gICAgICAgIF8uZWFjaChpZHMsIGZ1bmN0aW9uICh1c2VySWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyID0gdGhpcy51c2Vycy5nZXRCeUlkKHVzZXJJZCk7XG4gICAgICAgICAgICB1c2VyLnNldCgnd29ybGQnLCAnJyk7XG4gICAgICAgICAgICB1c2VyLnNldCgncm9sZScsICcnKTtcbiAgICAgICAgICAgIHF1ZXVlLmFkZChfLnBhcnRpYWwoXy5iaW5kKHRoaXMud29ybGRzLnVwZGF0ZVVzZXIsIHRoaXMud29ybGRzKSwgdXNlcikpO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIHVzYXNzaWduU2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICB2YXIgaWRzID0gdGhpcy5nZXRTZWxlY3RlZElkcygpO1xuXG4gICAgICAgIHZhciBkb25lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy53b3JsZHMuZmV0Y2goKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9oaWRlVXBkYXRpbmcoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudW5hc3NpZ25Vc2VycyhpZHMpLnRoZW4oZG9uZSk7XG4gICAgfSxcblxuICAgIG1ha2VVc2VySW5hY3RpdmU6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdmFyIGlkcyA9IHRoaXMuZ2V0U2VsZWN0ZWRJZHMoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIG1ha2VVc2Vyc0luYWN0aXZlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJvd3MgPSB0aGlzLmZpbmRSb3dWaWV3cyhpZHMpO1xuICAgICAgICAgICAgLy8gZm9yIG5vdyB3ZSBuZWVkIHRvIHNlcXVlbmNlIHRoZSBjYWxscyB0byBwYXRjaCB0aGUgdXNlcnNcbiAgICAgICAgICAgIC8vIHNpbmNlIHRoZSBBUEkgY2FuIG9ubHkgb3BlcmF0ZSBvbiBvbmUgY2FsbCBwZXIgZ3JvdXAgYXQgYSB0aW1lXG4gICAgICAgICAgICB2YXIgcXVldWUgPSBuZXcgQWpheFF1ZXVlKCk7XG4gICAgICAgICAgICBfLmVhY2gocm93cywgZnVuY3Rpb24gKHZpZXcpIHtcbiAgICAgICAgICAgICAgICB2YXIgdXNlciA9IHZpZXcubW9kZWw7XG4gICAgICAgICAgICAgICAgcXVldWUuYWRkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZpZXcubWFrZUluYWN0aXZlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZXcucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gdGhpcy51bmFzc2lnblVzZXJzKGlkcylcbiAgICAgICAgICAgIC50aGVuKG1ha2VVc2Vyc0luYWN0aXZlKTtcblxuXG4gICAgfSxcblxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiQoJ3RhYmxlIHRib2R5JykuZW1wdHkoKTtcbiAgICAgICAgdGhpcy5yZW5kZXJUYWJsZSgpO1xuICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgIH0sXG5cbiAgICByZW5kZXJUYWJsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJvd1ZpZXdzID0ge307XG4gICAgICAgIHZhciByb3dzID0gW107XG4gICAgICAgIHRoaXMudXNlcnMuZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgQXNzaWduZW1udFJvdyh7IG1vZGVsOiB1LCB3b3JsZHM6IHRoaXMud29ybGRzLCBwcm9qZWN0OiB0aGlzLnByb2plY3QgfSk7XG4gICAgICAgICAgICB0aGlzLnJvd1ZpZXdzW3UuZ2V0KCdpZCcpXSA9IHZpZXc7XG4gICAgICAgICAgICByb3dzLnB1c2godmlldy5yZW5kZXIoKS5lbCk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHRoaXMuJCgndGFibGUgdGJvZHknKS5hcHBlbmQocm93cyk7XG4gICAgfSxcblxuXG4gICAgdXBkYXRlQ29udHJvbHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9sc0ZvclNlbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnVwZGF0ZUF1dG9Bc3NpZ25CdXR0b24oKTtcbiAgICAgICAgdGhpcy51cGRhdGVTdGF0dXMoKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlU3RhdHVzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbmNvbHBsZXRlV29ybGRzID0gdGhpcy53b3JsZHMuZ2V0SW5jb21wbGV0ZVdvcmxkc0NvdW50KCk7XG4gICAgICAgIHZhciB1bmFzc2lnbmVkVXNlcnMgPSB0aGlzLnVzZXJzLmdldFVuYXNzaWduZWRVc2Vyc0NvdW50KCk7XG4gICAgICAgIHZhciB0b3RhbFdvcmxkcyA9IHRoaXMud29ybGRzLnNpemUoKTtcblxuICAgICAgICB2YXIgdXNlcnNUZXh0ID0gdW5hc3NpZ25lZFVzZXJzID8gdW5hc3NpZ25lZFVzZXJzID09PSAxID8gJzEgdXNlciBuZWVkcyBhc3NpZ25tZW50LicgOiB1bmFzc2lnbmVkVXNlcnMgKyAnIHVzZXJzIG5lZWQgYXNzaWdubWVudC4nIDogJ0FsbCB1c2VycyBoYXZlIGJlZW4gYXNzaWduZWQuJztcbiAgICAgICAgdmFyIHdvcmxkc1RleHQgPSAhdG90YWxXb3JsZHMgPyAnTm8gd29ybGRzIGhhdmUgYmVlbiBjcmVhdGVkLicgOiAhaW5jb2xwbGV0ZVdvcmxkcyA/ICdBbGwgd29ybGRzIGFyZSBjb21wbGV0ZS4nIDogaW5jb2xwbGV0ZVdvcmxkcyA9PT0gMSA/ICcxIGluY29tcGxldGUgd29ybGQgbmVlZHMgYXR0ZW50aW9uLicgOiBpbmNvbHBsZXRlV29ybGRzICsgJyBpbmNvbXBsZXRlIHdvcmxkcyBuZWVkIGF0dGVudGlvbi4nO1xuXG4gICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cyAudGV4dCcpLnRleHQodXNlcnNUZXh0KTtcbiAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cyAudGV4dCcpLnRleHQod29ybGRzVGV4dCk7XG5cbiAgICAgICAgaWYgKHVuYXNzaWduZWRVc2Vycykge1xuICAgICAgICAgICAgdGhpcy4kKCcjdXNlcnMtc3RhdHVzJykuYWRkQ2xhc3MoJ2luY29tcGxldGUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5jb2xwbGV0ZVdvcmxkcyB8fCAhdG90YWxXb3JsZHMpIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3dvcmxkcy1zdGF0dXMnKS5hZGRDbGFzcygnaW5jb21wbGV0ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLiQoJy5zdGF0dXMtd2lkZ2V0JykuYWRkQ2xhc3MoJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQ29udHJvbHNGb3JTZWxlY3Rpb246IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG51bVNlbGVjdGVkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpLmxlbmd0aDtcbiAgICAgICAgdGhpcy4kKCcuY29tcG9uZW50LmNvbnRyb2xzJylbbnVtU2VsZWN0ZWQgPyAnYWRkQ2xhc3MnIDogJ3JlbW92ZUNsYXNzJ10oJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQXV0b0Fzc2lnbkJ1dHRvbjogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIGlmICh0aGlzLnByb2plY3QuaXNEeW5hbWljQXNzaWdubWVudCgpKSB7XG4gICAgICAgICAgICB2YXIgaGFzUm9sZXMgPSB0aGlzLnByb2plY3QuaGFzUm9sZXMoKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5zaW5nbGUnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYycpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5keW5hbWljLW5vLXJvbGVzLXRleHQnKVtoYXNSb2xlcyA/ICdoaWRlJyA6ICdzaG93J10oKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpW2hhc1JvbGVzID8gJ2hpZGUnIDogJ3Nob3cnXSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLmR5bmFtaWMnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYy1uby1yb2xlcy10ZXh0JykuaGlkZSgpO1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLnNpbmdsZScpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpLnNob3coKTtcblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudXNlcnMuYWxsVXNlcnNBc3NpZ25lZCgpKSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLnJlbW92ZUNsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLmFkZENsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc2VsZWN0QWxsOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICB0aGlzLiQoJ3Rib2R5IDpjaGVja2JveCcpLnByb3AoJ2NoZWNrZWQnLCBlLnRhcmdldC5jaGVja2VkKTtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICB0b2dnbGVDb250cm9sbHM6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB0b3RhbCA9IHRoaXMuJCgndGJvZHkgOmNoZWNrYm94Jyk7XG4gICAgICAgIHZhciBjaGVja2VkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpO1xuXG4gICAgICAgIGlmICh0b3RhbC5sZW5ndGggPT09IGNoZWNrZWQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykuYXR0cignY2hlY2tlZCcsICdjaGVja2VkJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykucmVtb3ZlQXR0cignY2hlY2tlZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICBfc2hvd1VwZGF0aW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLmNzcyh7IG9wYWNpdHk6IDAuNCB9KTtcbiAgICB9LFxuXG4gICAgX2hpZGVVcGRhdGluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5jc3MoeyBvcGFjaXR5OiAxIH0pO1xuICAgIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBc3NpZ25tZW50OyIsIid1c2Ugc3RyaWN0JztcblxudmFyIEJhc2VDb2xsZWN0aW9uID0gZnVuY3Rpb24gKG1vZGVscywgb3B0aW9ucykge1xuICAgIHRoaXMuX21vZGVscyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlQ29sbGVjdGlvbi5wcm90b3R5cGUsIHtcbiAgICBpZEF0dHJpYnV0ZTogJ2lkJyxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uIChtb2RlbHMsIG9wdGlvbnMpIHtcbiAgICB9LFxuXG4gICAgY3JlYXRlOiBmdW5jdGlvbiAoYXR0ciwgb3B0aW9ucykge1xuICAgICAgICB2YXIgbSA9IG5ldyB0aGlzLm1vZGVsKGF0dHIsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnNldChtKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAobW9kZWxzLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMuX21vZGVscy5sZW5ndGggPSAwO1xuICAgICAgICB0aGlzLnNldChtb2RlbHMpO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uIChtb2RlbCkge1xuICAgICAgICBfLnJlbW92ZSh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbSA9PT0gbW9kZWw7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGRlbGV0ZSBtb2RlbC5jb2xsZWN0aW9uO1xuXG4gICAgICAgIHJldHVybiBtb2RlbDtcbiAgICB9LFxuXG4gICAgc2V0OiBmdW5jdGlvbiAobW9kZWxzKSB7XG4gICAgICAgIGlmICghbW9kZWxzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBtb2RlbHMgPSBbXS5jb25jYXQobW9kZWxzKTtcblxuICAgICAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIF8uZWFjaChtb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICBpZiAoIShtIGluc3RhbmNlb2YgdGhpcy5tb2RlbCkpIHtcbiAgICAgICAgICAgICAgICBtID0gbmV3IHRoaXMubW9kZWwobSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG0uY29sbGVjdGlvbiA9IHRoaXM7XG5cbiAgICAgICAgICAgIHRoaXMuX21vZGVscy5wdXNoKG0pO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICB0aGlzLnNvcnQuY2FsbCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gbW9kZWxzO1xuICAgIH0sXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBiLl9kYXRhW3RoaXMuaWRBdHRyaWJ1dGVdIC0gYS5fZGF0YVt0aGlzLmlkQXR0cmlidXRlXTtcbiAgICB9LFxuXG4gICAgc29ydDogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLl9tb2RlbHMgPSB0aGlzLl9tb2RlbHMuc29ydCh0aGlzLnNvcnRGbi5iaW5kKHRoaXMpKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzO1xuICAgIH0sXG5cbiAgICBnZXRCeUlkOiBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgcmV0dXJuIF8uZmluZCh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbS5nZXQodGhpcy5pZEF0dHJpYnV0ZSkgPT09IGlkO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgZWFjaDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uZWFjaCh0aGlzLl9tb2RlbHMsIGNiLCBjdHggfHwgdGhpcyk7XG4gICAgfSxcblxuICAgIGFsbDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uYWxsKHRoaXMuX21vZGVscywgY2IsIGN0eCB8fCB0aGlzKTtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBfLmludm9rZSh0aGlzLl9tb2RlbHMsICd0b0pTT04nKTtcbiAgICB9LFxuXG4gICAgZmluZDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbmQodGhpcy5fbW9kZWxzLCBmbik7XG4gICAgfSxcblxuICAgIGZpbHRlcjogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbHRlcih0aGlzLl9tb2RlbHMsIGZuKTtcbiAgICB9LFxuXG4gICAgc2l6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgbWFwOiBmdW5jdGlvbiAoZm4sIGN0eCkge1xuICAgICAgICByZXR1cm4gXy5tYXAodGhpcy5fbW9kZWxzLCBmdW5jdGlvbiAobW9kZWwpIHtcbiAgICAgICAgICAgIHJldHVybiBmbi5jYWxsKGN0eCwgbW9kZWwudG9KU09OKCkpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgcGx1Y2s6IGZ1bmN0aW9uIChmaWVsZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBtW2ZpZWxkXTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlQ29sbGVjdGlvbjsiLCIndXNlIHN0cmljdCc7XG5cblxudmFyIEJhc2VNb2RlbCA9IGZ1bmN0aW9uIChhdHRyLCBvcHRpb25zKSB7XG4gICAgYXR0ciA9IF8uZGVmYXVsdHMoe30sIGF0dHIsIF8ucmVzdWx0KHRoaXMsICdkZWZhdWx0cycpKTtcbiAgICB0aGlzLl9kYXRhID0ge307XG4gICAgdGhpcy5zZXQoYXR0ciwgb3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlTW9kZWwucHJvdG90eXBlLCB7XG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKGF0dHIsIG9wdGlvbnMpIHtcblxuICAgIH0sXG5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbCwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChrZXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWw7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBfLmV4dGVuZCh0aGlzLl9kYXRhLCBhdHRycyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGdldDogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YVtrZXldO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jb2xsZWN0aW9uLnJlbW92ZSh0aGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICB0b0pTT046IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGE7XG4gICAgfSxcblxuICAgIHBpY2s6IGZ1bmN0aW9uIChrZXlzKSB7XG4gICAgICAgIHJldHVybiBfLnBpY2sodGhpcy5fZGF0YSwga2V5cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlTW9kZWw7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZW52ID0ge1xuICAgIGFjY291bnQ6ICcnLFxuICAgIHByb2plY3Q6ICcnLFxuICAgIGdyb3VwOiAnJyxcbiAgICBncm91cElkOiAnJyxcbiAgICB0b2tlbjogJycsXG4gICAgc2VydmVyOiB7XG4gICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgcHJvdG9jb2w6ICdodHRwcydcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBzZXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGVudiA9IF8ubWVyZ2UoZW52LCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBlbnY7XG4gICAgfVxufTsiLCIoZnVuY3Rpb24gKCkge1xuICAgICd1c2Ugc3RyaWN0JztcbiAgICB2YXIgQXBwID0gcmVxdWlyZSgnLi9hc3NpZ25tZW50LmpzJyk7XG5cbiAgICB3aW5kb3cuZm9yaW8gPSB3aW5kb3cuZm9yaW8gfHwge307XG4gICAgd2luZG93LmZvcmlvLk11bHRpcGxheWVyQXNzaWdubWVudENvbXBvbmVudCA9IEFwcDtcbn0pKCk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBzZXJ2aWNlTG9jYXRvciA9IHJlcXVpcmUoJy4vc2VydmljZS1sb2NhdG9yJyk7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG4vLyB2YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBpc0R5bmFtaWNBc3NpZ25tZW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldCgnd29ybGRzJykgPT09ICdkeW5hbWljJztcbiAgICB9LFxuXG4gICAgaGFzUm9sZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJvbGVzID0gdGhpcy5nZXQoJ3JvbGVzJyk7XG4gICAgICAgIHJldHVybiByb2xlcyAmJiAhIXJvbGVzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGFwaSA9IHNlcnZpY2VMb2NhdG9yLndvcmxkQXBpKCk7XG5cbiAgICAgICAgcmV0dXJuIGFwaS5nZXRQcm9qZWN0U2V0dGluZ3MoKS50aGVuKGZ1bmN0aW9uIChzZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5zZXQoc2V0dGluZ3MpO1xuICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cbn0pOyIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVudiA9IHJlcXVpcmUoJy4vZGVmYXVsdHMuanMnKTtcblxudmFyIGNhY2hlID0ge307XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHdvcmxkQXBpOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghY2FjaGUud29ybGRBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLndvcmxkQXBpID0gbmV3IEYuc2VydmljZS5Xb3JsZChlbnYuZ2V0KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLndvcmxkQXBpO1xuICAgIH0sXG5cbiAgICBtZW1iZXJBcGk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFjYWNoZS5tZW1iZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLm1lbWJlckFwaSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKF8ucGljayhlbnYuZ2V0KCksIFsnZ3JvdXBJZCcsICdzZXJ2ZXInXSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLm1lbWJlckFwaTtcbiAgICB9LFxuXG4gICAgdXNlckFwaTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIWNhY2hlLnVzZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLnVzZXJBcGkgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoXy5waWNrKGVudi5nZXQoKSwgWydhY2NvdW50JywgJ3NlcnZlciddKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2FjaGUudXNlckFwaTtcbiAgICB9XG59OyIsImV4cG9ydHNbXCJlZGl0LXVzZXItcm93XCJdID0gZnVuY3Rpb24ob2JqKSB7XG5vYmogfHwgKG9iaiA9IHt9KTtcbnZhciBfX3QsIF9fcCA9ICcnLCBfX2UgPSBfLmVzY2FwZSwgX19qID0gQXJyYXkucHJvdG90eXBlLmpvaW47XG5mdW5jdGlvbiBwcmludCgpIHsgX19wICs9IF9fai5jYWxsKGFyZ3VtZW50cywgJycpIH1cbndpdGggKG9iaikge1xuX19wICs9ICc8dGQ+PGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGNsYXNzPVwic2VsZWN0XCIgZGF0YS1pZD1cIicgK1xuKChfX3QgPSAoIGlkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+PC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cIndvcmxkc1wiIGNsYXNzPVwiZm9ybS1jb250cm9sXCIgZGF0YS1maWVsZD1cIndvcmxkXCI+XFxuXFxuICAgICc7XG4gXy5lYWNoKHdvcmxkcywgZnVuY3Rpb24gKHcpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHcgPT09IHdvcmxkID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIicgK1xuKChfX3QgPSAoIG5ld1dvcmxkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiIGNsYXNzPVwibmV3LXdvcmxkLXRleHRcIj48aT4nICtcbigoX190ID0gKCBuZXdXb3JsZCApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbicgLSBOZXcgLTwvaT48L29wdGlvbj5cXG4gICAgPC9zZWxlY3Q+XFxuPC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cInJvbGVzXCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBkYXRhLWZpZWxkPVwicm9sZVwiPlxcbiAgICAnO1xuIF8uZWFjaChyb2xlcywgZnVuY3Rpb24gKHIpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHIgPT09IHJvbGUgPyAnc2VsZWN0ZWQnIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPicgK1xuKChfX3QgPSAoIHIgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC9vcHRpb24+XFxuICAgICc7XG4gfSk7IDtcbl9fcCArPSAnXFxuXFxuICAgICc7XG4gXy5lYWNoKG9wdGlvbmFsUm9sZXMsIGZ1bmN0aW9uIChyKSB7IDtcbl9fcCArPSAnXFxuICAgICAgICA8b3B0aW9uIHZhbHVlPVwiJyArXG4oKF9fdCA9ICggciApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbidcIiAnICtcbigoX190ID0gKCByID09PSByb2xlID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJyA8aT4oT3B0aW9uYWwpPC9pPjwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICA8L3NlbGVjdD5cXG48L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi10b29scyBidG4tc2F2ZSBzYXZlXCI+U2F2ZTwvYnV0dG9uPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi10b29scyBidG4tY2FuY2VsIGNhbmNlbFwiPkNhbmNlbDwvYnV0dG9uPlxcbjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTtcbmV4cG9ydHNbXCJ1c2VyLXJvd1wiXSA9IGZ1bmN0aW9uKG9iaikge1xub2JqIHx8IChvYmogPSB7fSk7XG52YXIgX190LCBfX3AgPSAnJywgX19lID0gXy5lc2NhcGU7XG53aXRoIChvYmopIHtcbl9fcCArPSAnPHRkPjxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cInNlbGVjdFwiIGRhdGEtaWQ9XCInICtcbigoX190ID0gKCBpZCkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggIWlzV29ybGRDb21wbGV0ZSA/ICc8ZW0gY2xhc3M9XCJmLWljb24gZi13YXJuaW5nXCI+PC9lbT4nIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggd29ybGQgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggcm9sZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPjxidXR0b24gY2xhc3M9XCJidG4gZWRpdCBidG4tZWRpdCBidG4tdG9vbHMgYXV0by1oaWRlXCI+RWRpdDwvYnV0dG9uPjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBkZWZhdWx0czoge1xuICAgICAgICB3b3JsZDogJycsXG4gICAgICAgIHJvbGU6ICcnLFxuICAgICAgICBhY3RpdmU6IHRydWUsXG4gICAgICAgIGlzV29ybGRDb21wbGV0ZTogdHJ1ZSxcbiAgICAgICAgZmlyc3ROYW1lOiAnJyxcbiAgICAgICAgbGFzdE5hbWU6ICcnXG4gICAgfSxcblxuICAgIG1ha2VBY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gbWVtYmVyQXBpLm1ha2VVc2VyQWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBtYWtlSW5hY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBmYWxzZSk7XG5cbiAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5tYWtlVXNlckluYWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cblxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcblxudmFyIE1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcblxuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBtb2RlbDogTW9kZWwsXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHZhciBhdyA9IGEuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBidyA9IGIuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIGlmIChhdyAhPT0gYncpIHtcbiAgICAgICAgICAgIHJldHVybiBhdyA8IGJ3ID8gLTEgOiAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGIuZ2V0KCd1c2VyTmFtZScpID4gYS5nZXQoJ3VzZXJOYW1lJykgPyAtMSA6IDE7XG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJC5hamF4U2V0dXAoe1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIGVudi5nZXQoKS50b2tlblxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgYWxsVXNlcnNBc3NpZ25lZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hbGwoZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiAhIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0VW5hc3NpZ25lZFVzZXJzQ291bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmlsdGVyKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICByZXR1cm4gIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KS5sZW5ndGg7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBncm91cElkID0gZW52LmdldCgpLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGdldEdyb3VwVXNlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbWVtYmVyQXBpID0gc2VydmljZUxvY2F0b3IubWVtYmVyQXBpKCk7XG4gICAgICAgICAgICB2YXIgdXNlckFwaSA9IHNlcnZpY2VMb2NhdG9yLnVzZXJBcGkoKTtcblxuICAgICAgICAgICAgdmFyIGxvYWRHcm91cE1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5nZXRHcm91cERldGFpbHMoKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBsb2FkVXNlcnNJbmZvID0gZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vbkZhY0FuZEFjdGl2ZSA9IGZ1bmN0aW9uICh1KSB7IHJldHVybiB1LmFjdGl2ZSAmJiB1LnJvbGUgIT09ICdmYWNpbGl0YXRvcic7IH07XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJzID0gXy5wbHVjayhfLmZpbHRlcihncm91cC5tZW1iZXJzLCBub25GYWNBbmRBY3RpdmUpLCAndXNlcklkJyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVzZXJBcGkuZ2V0KHsgaWQ6IHVzZXJzIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGxvYWRHcm91cE1lbWJlcnMoKVxuICAgICAgICAgICAgICAgIC50aGVuKGxvYWRVc2Vyc0luZm8pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgZ2V0R3JvdXBVc2VycygpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAodXNlcnMpIHtcbiAgICAgICAgICAgICAgICB1c2VycyA9IF8ubWFwKHVzZXJzLCBmdW5jdGlvbiAodSkgeyByZXR1cm4gXy5leHRlbmQodSwgeyBncm91cElkOiBncm91cElkIH0pOyB9KTtcbiAgICAgICAgICAgICAgICBfdGhpcy5zZXQodXNlcnMpO1xuICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHVzZXJzLCBfdGhpcyk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9XG5cbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBkZWZhdWx0czoge1xuICAgICAgICB1c2VyczogbnVsbCxcbiAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX19zdXBlci5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgdGhpcy5fZGF0YS51c2VycyA9IHRoaXMuX2RhdGEudXNlcnMgfHwgW107XG5cbiAgICAgICAgdGhpcy5fd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuXG4gICAgICAgIHZhciBpZCA9IHRoaXMuZ2V0KCdpZCcpO1xuICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgYWRkVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIHVzZXJzLnB1c2godXNlcik7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuc2F2ZSgpO1xuICAgIH0sXG5cbiAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlcikge1xuICAgICAgICB2YXIgaWQgPSB0aGlzLmdldCgnaWQnKTtcbiAgICAgICAgdmFyIGNoZWNrV29ybGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuZ2V0KCd1c2VycycpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSkuZGVsZXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICBfLnJlbW92ZSh0aGlzLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiB1LmdldCgnaWQnKSA9PT0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl93b3JsZEFwaVxuICAgICAgICAgICAgLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSlcbiAgICAgICAgICAgIC5yZW1vdmVVc2VyKHsgdXNlcklkOiB1c2VyLmdldCgnaWQnKSB9KVxuICAgICAgICAgICAgLnRoZW4oY2hlY2tXb3JsZCk7XG4gICAgfSxcblxuICAgIHNhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIG1hcFVzZXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIF8ubWFwKHRoaXMuZ2V0KCd1c2VycycpLCBmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgICAgIHZhciByZXMgPSB7IHVzZXJJZDogdS5nZXQoJ2lkJykgfTtcbiAgICAgICAgICAgICAgICB2YXIgcm9sZSA9IHUuZ2V0KCdyb2xlJyk7XG5cbiAgICAgICAgICAgICAgICBpZiAocm9sZSkge1xuICAgICAgICAgICAgICAgICAgICByZXMucm9sZSA9IHJvbGU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIGNyZWF0ZVdvcmxkID0gXy5wYXJ0aWFsKHRoaXMuX3dvcmxkQXBpLmNyZWF0ZSwgdGhpcy5waWNrKFsnbW9kZWwnLCAnbmFtZScsICdtaW5Vc2VycyddKSk7XG4gICAgICAgIHZhciBhZGRVc2VycyA9IF8ucGFydGlhbChfdGhpcy5fd29ybGRBcGkuYWRkVXNlcnMsIG1hcFVzZXJzKCksIHsgZmlsdGVyOiBfdGhpcy5nZXQoJ2lkJykgfSk7XG4gICAgICAgIHZhciBzYXZlZFVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIGlmICh0aGlzLmlzTmV3KCkpIHtcbiAgICAgICAgICAgIC8vIHdlIG5lZWQgdG8gY3JlYXRlIHRoZSB3b3JsZCBpbiB0aGUgQVBJIGFuZCB0aGVuIGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVXb3JsZCgpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNldCh3b3JsZCk7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLl93b3JsZEFwaS51cGRhdGVDb25maWcoeyBmaWx0ZXI6IHdvcmxkLmlkIH0pO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oYWRkVXNlcnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHVzZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHNpbmNlIHdlIHJlLXNldCB0aGUgd29ybGQsIHJlLXNldCB0aGUgdXNlcnNcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuc2V0KCd1c2VycycsIHNhdmVkVXNlcnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gdGhlIHdvcmxkIGlzIGFscmVhZHkgY3JlYXRlZCBqdXN0IGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBhZGRVc2VycygpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGlzTmV3OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5nZXQoJ2xhc3RNb2RpZmllZCcpO1xuICAgIH1cblxufSk7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgTW9kZWwgPSByZXF1aXJlKCcuL3dvcmxkLW1vZGVsJyk7XG52YXIgVXNlck1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG52YXIgZG9uZUZuID0gZnVuY3Rpb24gKGR0ZCwgYWZ0ZXIpIHtcbiAgICByZXR1cm4gXy5hZnRlcihhZnRlciwgZHRkLnJlc29sdmUpO1xufTtcblxudmFyIHdvcmxkQXBpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgbW9kZWw6IE1vZGVsLFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBfX3N1cGVyLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuICAgIH0sXG5cbiAgICBhdXRvQXNzaWduQWxsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gd29ybGRBcGkuYXV0b0Fzc2lnbihvcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzZXQodGhpcy5wYXJzZSh3b3JsZHMpKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGdldEluY29tcGxldGVXb3JsZHNDb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24gKHcpIHtcbiAgICAgICAgICAgIHJldHVybiAhdy5nZXQoJ2NvbXBsZXRlJyk7XG4gICAgICAgIH0pLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgdXBkYXRlVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHdvcmxkTmFtZSA9IHVzZXIuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgcHJldldvcmxkID0gdGhpcy5nZXRXb3JsZEJ5VXNlcih1c2VyKTtcbiAgICAgICAgdmFyIGN1cldvcmxkID0gdGhpcy5nZXRPckNyZWF0ZVdvcmxkKHdvcmxkTmFtZSk7XG4gICAgICAgIHZhciBkb25lID0gZG9uZUZuKGR0ZCwgMSk7XG5cbiAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUncyBhbnl0aGluZyB0byBkb1xuICAgICAgICBpZiAoIXByZXZXb3JsZCAmJiAhY3VyV29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiBkdGQucmVzb2x2ZSgpLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwcmV2V29ybGQpIHtcbiAgICAgICAgICAgIHByZXZXb3JsZC5yZW1vdmVVc2VyKHVzZXIpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY3VyV29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjdXJXb3JsZC5hZGRVc2VyKHVzZXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAudGhlbihkb25lKTtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJXb3JsZCkge1xuICAgICAgICAgICAgY3VyV29ybGQuYWRkVXNlcih1c2VyKVxuICAgICAgICAgICAgICAgIC50aGVuKGRvbmUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldE9yQ3JlYXRlV29ybGQ6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgaWYgKCF3b3JsZE5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB3b3JsZCA9IHRoaXMuZ2V0V29yZEJ5TmFtZSh3b3JsZE5hbWUpO1xuXG4gICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgIHdvcmxkID0gdGhpcy5jcmVhdGUoeyBuYW1lOiB3b3JsZE5hbWUgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gd29ybGQ7XG4gICAgfSxcblxuICAgIGdldFdvcmRCeU5hbWU6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmluZChmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiB3b3JsZC5nZXQoJ25hbWUnKSA9PT0gd29ybGROYW1lO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGRCeVVzZXI6IGZ1bmN0aW9uICh1c2VyKSB7XG4gICAgICAgIGlmICghdXNlci5nZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZ2V0V29ybGRCeVVzZXIgZXhwZWN0ZXMgYSBtb2RlbCAoJyArIHVzZXIgKyAnKScpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGlkID0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFdvcmxkQnlVc2VySWQoaWQpO1xuICAgIH0sXG5cbiAgICBnZXRXb3JsZEJ5VXNlcklkOiBmdW5jdGlvbiAodXNlcklkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZpbmQoZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICByZXR1cm4gXy5maW5kKHdvcmxkLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdS5nZXQoJ2lkJykgPT09IHVzZXJJZDtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGROYW1lczogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wbHVjaygnbmFtZScpO1xuICAgIH0sXG5cbiAgICBnZXROZXh0V29ybGROYW1lOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBwYWQgPSBmdW5jdGlvbiAobnVtLCBwbGFjZXMpIHtcbiAgICAgICAgICAgIHZhciB6ZXJvcyA9ICcwMDAwMDAwMDAwMDAwMDAwMDAnO1xuICAgICAgICAgICAgdmFyIGRpZ2l0cyA9IG51bS50b1N0cmluZygpLmxlbmd0aDtcbiAgICAgICAgICAgIHZhciBuZWVkZWQgPSBwbGFjZXMgLSBkaWdpdHM7XG4gICAgICAgICAgICByZXR1cm4gemVyb3Muc3Vic3RyKDAsIG5lZWRlZCkgKyBudW07XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHdvcmxkcyA9IHRoaXMuZ2V0V29ybGROYW1lcygpO1xuXG4gICAgICAgIGlmICghd29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuICdXb3JsZDAwMSc7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcHJvcGVyTmFtZXMgPSBfLmZpbHRlcih3b3JsZHMsIGZ1bmN0aW9uICh3KSB7IHJldHVybiAvV29ybGRcXGRcXGRcXGQvLnRlc3Qodyk7IH0pLnNvcnQoKTtcbiAgICAgICAgdmFyIGxhc3RXb3JsZCA9IHByb3Blck5hbWVzW3Byb3Blck5hbWVzLmxlbmd0aCAtIDFdO1xuICAgICAgICB2YXIgbnVtV29ybGQgPSArbGFzdFdvcmxkLm1hdGNoKC9Xb3JsZChcXGRcXGRcXGQpLylbMV07XG4gICAgICAgIHJldHVybiAnV29ybGQnICsgcGFkKG51bVdvcmxkICsgMSwgMyk7XG4gICAgfSxcblxuICAgIHNldFVzZXJzQ29sbGVjdGlvbjogZnVuY3Rpb24gKHVzZXJzQ29sbGVjdGlvbikge1xuICAgICAgICB0aGlzLnVzZXJzQ29sbGVjdGlvbiA9IHVzZXJzQ29sbGVjdGlvbjtcbiAgICB9LFxuXG4gICAgam9pblVzZXJzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1c2Vyc0hhc2ggPSB7fTtcbiAgICAgICAgdmFyIHVzZXJzQ29sbGVjdGlvbiA9IHRoaXMudXNlcnNDb2xsZWN0aW9uO1xuICAgICAgICB1c2Vyc0NvbGxlY3Rpb24uZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdS5zZXQoeyBpc1dvcmxkQ29tcGxldGU6IHRydWUgfSk7XG4gICAgICAgICAgICByZXR1cm4gKHVzZXJzSGFzaFt1LmdldCgnaWQnKV0gPSB1KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5lYWNoKGZ1bmN0aW9uICh3LCBpKSB7XG4gICAgICAgICAgICB2YXIgbmFtZSA9IHcuZ2V0KCduYW1lJyk7XG4gICAgICAgICAgICB2YXIgaXNDb21wbGV0ZSA9IHcuZ2V0KCdjb21wbGV0ZScpO1xuICAgICAgICAgICAgdy5zZXQoeyBpbmRleDogaSwgbmFtZTogbmFtZSB8fCAoaSArIDEpICsgJycgfSk7XG4gICAgICAgICAgICBfLmVhY2gody5nZXQoJ3VzZXJzJyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgaWYgKHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldKSB7XG4gICAgICAgICAgICAgICAgICAgIHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldLnNldCh7IHdvcmxkOiBuYW1lLCByb2xlOiB1LmdldCgncm9sZScpLCBpc1dvcmxkQ29tcGxldGU6IGlzQ29tcGxldGUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHVzZXJzQ29sbGVjdGlvbi5zb3J0KCk7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB3b3JsZEFwaS5saXN0KClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc2V0KHRoaXMucGFyc2Uod29ybGRzKSk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBwYXJzZTogZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICBpZiAod29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgd29ybGRzID0gXy5tYXAod29ybGRzLCBmdW5jdGlvbiAodykge1xuICAgICAgICAgICAgICAgIHZhciB1c2VycyA9IF8ubWFwKHcudXNlcnMsIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGluIHRoZSB3b3JsZCBhcGkgdXNlcnMgSWRzIGNvbWVzIGFzIHVzZXJJZFxuICAgICAgICAgICAgICAgICAgICAvLyBtYWtlIHN1cmUgd2UgYWRkIGl0IGFzIGlkIHNvIHdlIGNhbiB1c2UgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIHNhbWUgY29kZSB0byBhY2Nlc3MgbW9kZWxzIHRoYXQgY29tZSBmcm9tIHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyBtZW1iZXIvbG9jYWwgYXBpIGFzIHdpdGggdGhlIHdvcmxkIGFwaVxuICAgICAgICAgICAgICAgICAgICB1LmlkID0gdS51c2VySWQ7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVXNlck1vZGVsKHUpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgdy51c2VycyA9IHVzZXJzO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHc7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB3b3JsZHM7XG4gICAgfVxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuKiBVdGlsaXR5IGNsYXNzIHRvIG1ha2UgYWpheCBjYWxscyBzZXF1ZW5jaWFsXG4qL1xuZnVuY3Rpb24gQWpheFF1ZXVlICgpIHtcbiAgICB0aGlzLnF1ZXVlID0gW107XG59XG5cbiQuZXh0ZW5kKEFqYXhRdWV1ZS5wcm90b3R5cGUsIHtcbiAgICBhZGQ6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICByZXR1cm4gdGhpcy5xdWV1ZS5wdXNoKGZuKTtcbiAgICB9LFxuXG4gICAgZXhlY3V0ZTogZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgY29udGV4dCA9IGNvbnRleHQgfHwgdGhpcztcblxuICAgICAgICBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgICAgICAgaWYgKF90aGlzLnF1ZXVlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBmbiA9IF90aGlzLnF1ZXVlLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgICAgICBmbi5jYWxsKGNvbnRleHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKG5leHQpXG4gICAgICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbmV4dCgpO1xuXG4gICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQWpheFF1ZXVlOyIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiJdfQ== diff --git a/src/managers/auth-manager.js b/src/managers/auth-manager.js index e842a5d4..80a08124 100644 --- a/src/managers/auth-manager.js +++ b/src/managers/auth-manager.js @@ -70,6 +70,8 @@ function AuthManager(options) { this.options = $.extend(true, {}, defaults, options); var urlConfig = new ConfigService(this.options).get('server'); + this.isLocal = urlConfig.isLocalhost(); + if (!this.options.account) { this.options.account = urlConfig.accountPath; } @@ -146,7 +148,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { var projectName = (options && options.project) ? options.project : this.options.project; if (this.options.store.root === undefined && accountName && projectName) { - this.store.serviceOptions.root = '/app/' + accountName + '/' + projectName; + this.store.serviceOptions.root = this.isLocal ? '/' : '/app/' + accountName + '/' + projectName; } var decodeToken = function (token) { diff --git a/tests/spec/test-auth-manager.js b/tests/spec/test-auth-manager.js index 49e40d47..7e7758c9 100644 --- a/tests/spec/test-auth-manager.js +++ b/tests/spec/test-auth-manager.js @@ -52,6 +52,7 @@ account: 'accountName', project: 'projectName' }); + am.isLocal = false ; am.login(); am.store.serviceOptions.root.should.equal('/app/accountName/projectName'); }); @@ -59,6 +60,7 @@ describe('#setting cookies', function () { it ('creates cookie with the correct path name when passing in account info in login', function () { var am = new F.manager.AuthManager(); + am.isLocal = false; am.login({ account: 'accountName', project: 'projectName' From 1e01ede3a5cc8a3e4d1002796c197218de37bba9 Mon Sep 17 00:00:00 2001 From: Molly Jones Date: Fri, 26 Feb 2016 16:49:00 -0800 Subject: [PATCH 11/14] build components for branch, more testing --- dist/components/assignment/assignment.js | 2 +- dist/epicenter.js | 6 ++++-- dist/epicenter.min.js | 2 +- dist/epicenter.min.js.map | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/dist/components/assignment/assignment.js b/dist/components/assignment/assignment.js index 947e5bfa..74ae582d 100644 --- a/dist/components/assignment/assignment.js +++ b/dist/components/assignment/assignment.js @@ -1231,4 +1231,4 @@ module.exports = function (base, props, staticProps) { }; },{}]},{},[6]) -//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Fzc2lnbm1lbnQtcm93LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9hc3NpZ25tZW50LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9iYXNlLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Jhc2UtbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2RlZmF1bHRzLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9pbmRleC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvcHJvamVjdC1tb2RlbC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvc2VydmljZS1sb2NhdG9yLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy90ZW1wbGF0ZXMuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXItbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXJzLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3dvcmxkLW1vZGVsLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy93b3JsZHMtY29sbGVjdGlvbi5qcyIsInNyYy91dGlsL2FqYXgtcXVldWUuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCc7XG5cbnZhciB0ZW1wbGF0ZXMgPSByZXF1aXJlKCcuL3RlbXBsYXRlcycpO1xuXG52YXIgQXNzaWdubWVudFJvdyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy4kZWwgPSAkKCc8dHI+Jyk7XG4gICAgdGhpcy5lbCA9IHRoaXMuJGVsWzBdO1xuICAgIHRoaXMuJCA9IF8ucGFydGlhbFJpZ2h0KCQsIHRoaXMuJGVsKTtcblxuICAgIHRoaXMubW9kZWwgPSBvcHRpb25zLm1vZGVsO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy53b3JsZHMgPSBvcHRpb25zLndvcmxkcztcbiAgICB0aGlzLnByb2plY3QgPSBvcHRpb25zLnByb2plY3Q7XG5cbiAgICBfLmJpbmRBbGwodGhpcywgWydzZXRFZGl0TW9kZScsICdyZW1vdmVFZGl0TW9kZScsICdzYXZlRWRpdCcsICdjYW5jZWxFZGl0JywgJ3VwZGF0ZURhdGEnXSk7XG5cbiAgICB0aGlzLmJpbmRFdmVudHMoKTtcblxufTtcblxuXy5leHRlbmQoQXNzaWdubWVudFJvdy5wcm90b3R5cGUsIHtcblxuICAgIHRlbXBsYXRlOiB0ZW1wbGF0ZXNbJ3VzZXItcm93J10sXG5cbiAgICBlZGl0VGVtcGxhdGU6IHRlbXBsYXRlc1snZWRpdC11c2VyLXJvdyddLFxuXG4gICAgYmluZEV2ZW50czogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnYnV0dG9uLmVkaXQnLCB0aGlzLnNldEVkaXRNb2RlKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2J1dHRvbi5zYXZlJywgdGhpcy5zYXZlRWRpdCk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICdidXR0b24uY2FuY2VsJywgdGhpcy5jYW5jZWxFZGl0KTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9mZignY2xpY2snLCBudWxsLCBudWxsKTtcbiAgICAgICAgLy8gdGhpcyBvbmx5IGdpdmVzIGEgZGVsYXkgdG8gcmVtb3ZlIHRoZSB0clxuICAgICAgICAvLyBhbmltYXRpb24gb2YgaGVpZ2h0IG9mIHRoZSB0ciBkb2VzIG5vdCB3b3JrXG4gICAgICAgIHRoaXMuJCgnOmNoZWNrYm94JykuYXR0cignY2hlY2tlZCcsIGZhbHNlKTtcbiAgICAgICAgdGhpcy4kZWxcbiAgICAgICAgICAgIC5jc3MoeyBvcGFjaXR5OiAwLjMgfSlcbiAgICAgICAgICAgIC5hbmltYXRlKHsgaGVpZ2h0OiAwIH0sIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMzAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIG1ha2VJbmFjdGl2ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tb2RlbC5tYWtlSW5hY3RpdmUoKTtcbiAgICB9LFxuXG4gICAgc2V0RWRpdE1vZGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5tb2RlbC5zZXQoJ2VkaXQtbW9kZScsIHRydWUpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICByZW1vdmVFZGl0TW9kZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLm1vZGVsLnNldCgnZWRpdC1tb2RlJywgZmFsc2UpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICBzYXZlRWRpdDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB0aGlzLnVwZGF0ZURhdGEoKTtcbiAgICAgICAgdGhpcy53b3JsZHNcbiAgICAgICAgICAgIC51cGRhdGVVc2VyKHRoaXMubW9kZWwpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMucmVtb3ZlRWRpdE1vZGUoKTtcbiAgICAgICAgICAgICAgICBfdGhpcy4kZWwudHJpZ2dlcigndXBkYXRlJywgX3RoaXMpO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGNhbmNlbEVkaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVFZGl0TW9kZSgpO1xuICAgIH0sXG5cbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHRlbXBsID0gdGhpcy5tb2RlbC5nZXQoJ2VkaXQtbW9kZScpID8gdGhpcy5lZGl0VGVtcGxhdGUgOiB0aGlzLnRlbXBsYXRlO1xuICAgICAgICB2YXIgdm0gPSBfLmV4dGVuZCh7XG4gICAgICAgICAgICByb2xlczogdGhpcy5wcm9qZWN0LmdldCgncm9sZXMnKSxcbiAgICAgICAgICAgIG9wdGlvbmFsUm9sZXM6IHRoaXMucHJvamVjdC5nZXQoJ29wdGlvbmFsUm9sZXMnKSxcbiAgICAgICAgICAgIHdvcmxkczogdGhpcy53b3JsZHMuZ2V0V29ybGROYW1lcygpLFxuICAgICAgICAgICAgbmV3V29ybGQ6IHRoaXMud29ybGRzLmdldE5leHRXb3JsZE5hbWUoKVxuICAgICAgICB9LCB0aGlzLm1vZGVsLnRvSlNPTigpKTtcblxuICAgICAgICB0aGlzLiRlbC5odG1sKHRlbXBsKHZtKSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIHVwZGF0ZURhdGE6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdGhpcy4kKCdbZGF0YS1maWVsZF0nKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBlbCA9ICQodGhpcyk7XG4gICAgICAgICAgICB2YXIgZmllbGQgPSBlbC5kYXRhKCdmaWVsZCcpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IGVsLnZhbCgpO1xuXG4gICAgICAgICAgICBfdGhpcy5tb2RlbC5zZXQoZmllbGQsIHZhbCk7XG4gICAgICAgIH0pO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQXNzaWdubWVudFJvdzsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBVc2Vyc0NvbGxlY3Rpb24gPSByZXF1aXJlKCcuL3VzZXJzLWNvbGxlY3Rpb24nKTtcbnZhciBXb3JsZHNDb2xsZWN0aW9uID0gcmVxdWlyZSgnLi93b3JsZHMtY29sbGVjdGlvbicpO1xudmFyIFByb2plY3RNb2RlbCA9IHJlcXVpcmUoJy4vcHJvamVjdC1tb2RlbCcpO1xudmFyIEFzc2lnbmVtbnRSb3cgPSByZXF1aXJlKCcuL2Fzc2lnbm1lbnQtcm93Jyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIEFqYXhRdWV1ZSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvYWpheC1xdWV1ZScpO1xuXG5mdW5jdGlvbiBzZXRFbnZpcm9ubWVudChvcHRpb25zKSB7XG4gICAgZW52LnNldChfLm9taXQob3B0aW9ucywgJ2VsJykpO1xufVxuXG52YXIgQXNzaWdubWVudCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgc2V0RW52aXJvbm1lbnQob3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplKG9wdGlvbnMpO1xufTtcblxuQXNzaWdubWVudC5wcm90b3R5cGUgPSB7XG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLmVsID0gdHlwZW9mIG9wdGlvbnMuZWwgPT09ICdzdHJpbmcnID8gJChvcHRpb25zLmVsKVswXSA6IG9wdGlvbnMuZWw7XG4gICAgICAgIHRoaXMuJGVsID0gJCh0aGlzLmVsKTtcbiAgICAgICAgdGhpcy4kID0gXy5wYXJ0aWFsUmlnaHQoJCwgdGhpcy5lbCk7XG5cbiAgICAgICAgdGhpcy51c2VycyA9IG5ldyBVc2Vyc0NvbGxlY3Rpb24oKTtcbiAgICAgICAgdGhpcy53b3JsZHMgPSBuZXcgV29ybGRzQ29sbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnByb2plY3QgPSBuZXcgUHJvamVjdE1vZGVsKCk7XG5cbiAgICAgICAgXy5iaW5kQWxsKHRoaXMsIFsncmVuZGVyJywgJ3JlbmRlclRhYmxlJywgJ3RvZ2dsZUNvbnRyb2xscycsICdzYXZlRWRpdCcsICdzZWxlY3RBbGwnLCAndXNhc3NpZ25TZWxlY3RlZCcsICdfc2hvd1VwZGF0aW5nJywgJ19oaWRlVXBkYXRpbmcnLCAnYXV0b0Fzc2lnbkFsbCcsICdtYWtlVXNlckluYWN0aXZlJ10pO1xuXG4gICAgICAgIHRoaXMuYmluZEV2ZW50cygpO1xuICAgIH0sXG5cbiAgICBiaW5kRXZlbnRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9uKCd1cGRhdGUnLCAndHInLCB0aGlzLnNhdmVFZGl0KTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2lucHV0OmNoZWNrYm94Om5vdCgjc2VsZWN0LWFsbCknLCB0aGlzLnRvZ2dsZUNvbnRyb2xscyk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICcjc2VsZWN0LWFsbCcsIHRoaXMuc2VsZWN0QWxsKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy51bmFzc2lnbi11c2VyJywgdGhpcy51c2Fzc2lnblNlbGVjdGVkKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy5hdXRvLWFzc2lnbi1hbGwnLCB0aGlzLmF1dG9Bc3NpZ25BbGwpO1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnLm1ha2UtdXNlci1pbmFjdGl2ZScsIHRoaXMubWFrZVVzZXJJbmFjdGl2ZSk7XG4gICAgfSxcblxuICAgIGxvYWQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB2YXIgam9pbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLnNldFVzZXJzQ29sbGVjdGlvbih0aGlzLnVzZXJzKTtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLmpvaW5Vc2VycygpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHJldHVybiAkLndoZW4oXG4gICAgICAgICAgICB0aGlzLndvcmxkcy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy51c2Vycy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy5wcm9qZWN0LmZldGNoKClcbiAgICAgICAgKS50aGVuKGpvaW4pO1xuXG4gICAgfSxcblxuICAgIHNhdmVFZGl0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMud29ybGRzLmZldGNoKClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ29udHJvbHMoKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGF1dG9Bc3NpZ25BbGw6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG4gICAgICAgIHZhciBtYXhVc2VycyA9ICt0aGlzLiQoJyNtYXgtdXNlcnMnKS52YWwoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMud29ybGRzLmF1dG9Bc3NpZ25BbGwoeyBtYXhVc2VyczogbWF4VXNlcnMgfSlcbiAgICAgICAgICAgIC5kb25lKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC5mYWlsKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9LFxuXG4gICAgZ2V0U2VsZWN0ZWRJZHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuJCgndGJvZHkgOmNoZWNrYm94OmNoZWNrZWQnKS5tYXAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICQodGhpcykuZGF0YSgnaWQnKTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGZpbmRSb3dWaWV3czogZnVuY3Rpb24gKGlkcykge1xuICAgICAgICByZXR1cm4gXy5tYXAoaWRzLCBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJvd1ZpZXdzW2lkXTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfSxcblxuICAgIHVuYXNzaWduVXNlcnM6IGZ1bmN0aW9uIChpZHMpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIGZvciBub3cgd2UgbmVlZCB0byBzZXF1ZW5jZSB0aGUgY2FsbHMgdG8gdW5hc3NpZ24gdXNlcnMgZnJvbSB3b3JsZHNcbiAgICAgICAgdmFyIHF1ZXVlID0gbmV3IEFqYXhRdWV1ZSgpO1xuXG4gICAgICAgIF8uZWFjaChpZHMsIGZ1bmN0aW9uICh1c2VySWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyID0gdGhpcy51c2Vycy5nZXRCeUlkKHVzZXJJZCk7XG4gICAgICAgICAgICB1c2VyLnNldCgnd29ybGQnLCAnJyk7XG4gICAgICAgICAgICB1c2VyLnNldCgncm9sZScsICcnKTtcbiAgICAgICAgICAgIHF1ZXVlLmFkZChfLnBhcnRpYWwoXy5iaW5kKHRoaXMud29ybGRzLnVwZGF0ZVVzZXIsIHRoaXMud29ybGRzKSwgdXNlcikpO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIHVzYXNzaWduU2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICB2YXIgaWRzID0gdGhpcy5nZXRTZWxlY3RlZElkcygpO1xuXG4gICAgICAgIHZhciBkb25lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy53b3JsZHMuZmV0Y2goKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9oaWRlVXBkYXRpbmcoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudW5hc3NpZ25Vc2VycyhpZHMpLnRoZW4oZG9uZSk7XG4gICAgfSxcblxuICAgIG1ha2VVc2VySW5hY3RpdmU6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdmFyIGlkcyA9IHRoaXMuZ2V0U2VsZWN0ZWRJZHMoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIG1ha2VVc2Vyc0luYWN0aXZlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJvd3MgPSB0aGlzLmZpbmRSb3dWaWV3cyhpZHMpO1xuICAgICAgICAgICAgLy8gZm9yIG5vdyB3ZSBuZWVkIHRvIHNlcXVlbmNlIHRoZSBjYWxscyB0byBwYXRjaCB0aGUgdXNlcnNcbiAgICAgICAgICAgIC8vIHNpbmNlIHRoZSBBUEkgY2FuIG9ubHkgb3BlcmF0ZSBvbiBvbmUgY2FsbCBwZXIgZ3JvdXAgYXQgYSB0aW1lXG4gICAgICAgICAgICB2YXIgcXVldWUgPSBuZXcgQWpheFF1ZXVlKCk7XG4gICAgICAgICAgICBfLmVhY2gocm93cywgZnVuY3Rpb24gKHZpZXcpIHtcbiAgICAgICAgICAgICAgICB2YXIgdXNlciA9IHZpZXcubW9kZWw7XG4gICAgICAgICAgICAgICAgcXVldWUuYWRkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZpZXcubWFrZUluYWN0aXZlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZXcucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gdGhpcy51bmFzc2lnblVzZXJzKGlkcylcbiAgICAgICAgICAgIC50aGVuKG1ha2VVc2Vyc0luYWN0aXZlKTtcblxuXG4gICAgfSxcblxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiQoJ3RhYmxlIHRib2R5JykuZW1wdHkoKTtcbiAgICAgICAgdGhpcy5yZW5kZXJUYWJsZSgpO1xuICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgIH0sXG5cbiAgICByZW5kZXJUYWJsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJvd1ZpZXdzID0ge307XG4gICAgICAgIHZhciByb3dzID0gW107XG4gICAgICAgIHRoaXMudXNlcnMuZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgQXNzaWduZW1udFJvdyh7IG1vZGVsOiB1LCB3b3JsZHM6IHRoaXMud29ybGRzLCBwcm9qZWN0OiB0aGlzLnByb2plY3QgfSk7XG4gICAgICAgICAgICB0aGlzLnJvd1ZpZXdzW3UuZ2V0KCdpZCcpXSA9IHZpZXc7XG4gICAgICAgICAgICByb3dzLnB1c2godmlldy5yZW5kZXIoKS5lbCk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHRoaXMuJCgndGFibGUgdGJvZHknKS5hcHBlbmQocm93cyk7XG4gICAgfSxcblxuXG4gICAgdXBkYXRlQ29udHJvbHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9sc0ZvclNlbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnVwZGF0ZUF1dG9Bc3NpZ25CdXR0b24oKTtcbiAgICAgICAgdGhpcy51cGRhdGVTdGF0dXMoKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlU3RhdHVzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbmNvbHBsZXRlV29ybGRzID0gdGhpcy53b3JsZHMuZ2V0SW5jb21wbGV0ZVdvcmxkc0NvdW50KCk7XG4gICAgICAgIHZhciB1bmFzc2lnbmVkVXNlcnMgPSB0aGlzLnVzZXJzLmdldFVuYXNzaWduZWRVc2Vyc0NvdW50KCk7XG4gICAgICAgIHZhciB0b3RhbFdvcmxkcyA9IHRoaXMud29ybGRzLnNpemUoKTtcblxuICAgICAgICB2YXIgdXNlcnNUZXh0ID0gdW5hc3NpZ25lZFVzZXJzID8gdW5hc3NpZ25lZFVzZXJzID09PSAxID8gJzEgdXNlciBuZWVkcyBhc3NpZ25tZW50LicgOiB1bmFzc2lnbmVkVXNlcnMgKyAnIHVzZXJzIG5lZWQgYXNzaWdubWVudC4nIDogJ0FsbCB1c2VycyBoYXZlIGJlZW4gYXNzaWduZWQuJztcbiAgICAgICAgdmFyIHdvcmxkc1RleHQgPSAhdG90YWxXb3JsZHMgPyAnTm8gd29ybGRzIGhhdmUgYmVlbiBjcmVhdGVkLicgOiAhaW5jb2xwbGV0ZVdvcmxkcyA/ICdBbGwgd29ybGRzIGFyZSBjb21wbGV0ZS4nIDogaW5jb2xwbGV0ZVdvcmxkcyA9PT0gMSA/ICcxIGluY29tcGxldGUgd29ybGQgbmVlZHMgYXR0ZW50aW9uLicgOiBpbmNvbHBsZXRlV29ybGRzICsgJyBpbmNvbXBsZXRlIHdvcmxkcyBuZWVkIGF0dGVudGlvbi4nO1xuXG4gICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cyAudGV4dCcpLnRleHQodXNlcnNUZXh0KTtcbiAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cyAudGV4dCcpLnRleHQod29ybGRzVGV4dCk7XG5cbiAgICAgICAgaWYgKHVuYXNzaWduZWRVc2Vycykge1xuICAgICAgICAgICAgdGhpcy4kKCcjdXNlcnMtc3RhdHVzJykuYWRkQ2xhc3MoJ2luY29tcGxldGUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5jb2xwbGV0ZVdvcmxkcyB8fCAhdG90YWxXb3JsZHMpIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3dvcmxkcy1zdGF0dXMnKS5hZGRDbGFzcygnaW5jb21wbGV0ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLiQoJy5zdGF0dXMtd2lkZ2V0JykuYWRkQ2xhc3MoJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQ29udHJvbHNGb3JTZWxlY3Rpb246IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG51bVNlbGVjdGVkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpLmxlbmd0aDtcbiAgICAgICAgdGhpcy4kKCcuY29tcG9uZW50LmNvbnRyb2xzJylbbnVtU2VsZWN0ZWQgPyAnYWRkQ2xhc3MnIDogJ3JlbW92ZUNsYXNzJ10oJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQXV0b0Fzc2lnbkJ1dHRvbjogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIGlmICh0aGlzLnByb2plY3QuaXNEeW5hbWljQXNzaWdubWVudCgpKSB7XG4gICAgICAgICAgICB2YXIgaGFzUm9sZXMgPSB0aGlzLnByb2plY3QuaGFzUm9sZXMoKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5zaW5nbGUnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYycpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5keW5hbWljLW5vLXJvbGVzLXRleHQnKVtoYXNSb2xlcyA/ICdoaWRlJyA6ICdzaG93J10oKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpW2hhc1JvbGVzID8gJ2hpZGUnIDogJ3Nob3cnXSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLmR5bmFtaWMnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYy1uby1yb2xlcy10ZXh0JykuaGlkZSgpO1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLnNpbmdsZScpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpLnNob3coKTtcblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudXNlcnMuYWxsVXNlcnNBc3NpZ25lZCgpKSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLnJlbW92ZUNsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLmFkZENsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc2VsZWN0QWxsOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICB0aGlzLiQoJ3Rib2R5IDpjaGVja2JveCcpLnByb3AoJ2NoZWNrZWQnLCBlLnRhcmdldC5jaGVja2VkKTtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICB0b2dnbGVDb250cm9sbHM6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB0b3RhbCA9IHRoaXMuJCgndGJvZHkgOmNoZWNrYm94Jyk7XG4gICAgICAgIHZhciBjaGVja2VkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpO1xuXG4gICAgICAgIGlmICh0b3RhbC5sZW5ndGggPT09IGNoZWNrZWQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykuYXR0cignY2hlY2tlZCcsICdjaGVja2VkJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykucmVtb3ZlQXR0cignY2hlY2tlZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICBfc2hvd1VwZGF0aW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLmNzcyh7IG9wYWNpdHk6IDAuNCB9KTtcbiAgICB9LFxuXG4gICAgX2hpZGVVcGRhdGluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5jc3MoeyBvcGFjaXR5OiAxIH0pO1xuICAgIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBc3NpZ25tZW50OyIsIid1c2Ugc3RyaWN0JztcblxudmFyIEJhc2VDb2xsZWN0aW9uID0gZnVuY3Rpb24gKG1vZGVscywgb3B0aW9ucykge1xuICAgIHRoaXMuX21vZGVscyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlQ29sbGVjdGlvbi5wcm90b3R5cGUsIHtcbiAgICBpZEF0dHJpYnV0ZTogJ2lkJyxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uIChtb2RlbHMsIG9wdGlvbnMpIHtcbiAgICB9LFxuXG4gICAgY3JlYXRlOiBmdW5jdGlvbiAoYXR0ciwgb3B0aW9ucykge1xuICAgICAgICB2YXIgbSA9IG5ldyB0aGlzLm1vZGVsKGF0dHIsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnNldChtKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAobW9kZWxzLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMuX21vZGVscy5sZW5ndGggPSAwO1xuICAgICAgICB0aGlzLnNldChtb2RlbHMpO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uIChtb2RlbCkge1xuICAgICAgICBfLnJlbW92ZSh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbSA9PT0gbW9kZWw7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGRlbGV0ZSBtb2RlbC5jb2xsZWN0aW9uO1xuXG4gICAgICAgIHJldHVybiBtb2RlbDtcbiAgICB9LFxuXG4gICAgc2V0OiBmdW5jdGlvbiAobW9kZWxzKSB7XG4gICAgICAgIGlmICghbW9kZWxzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBtb2RlbHMgPSBbXS5jb25jYXQobW9kZWxzKTtcblxuICAgICAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIF8uZWFjaChtb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICBpZiAoIShtIGluc3RhbmNlb2YgdGhpcy5tb2RlbCkpIHtcbiAgICAgICAgICAgICAgICBtID0gbmV3IHRoaXMubW9kZWwobSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG0uY29sbGVjdGlvbiA9IHRoaXM7XG5cbiAgICAgICAgICAgIHRoaXMuX21vZGVscy5wdXNoKG0pO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICB0aGlzLnNvcnQuY2FsbCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gbW9kZWxzO1xuICAgIH0sXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBiLl9kYXRhW3RoaXMuaWRBdHRyaWJ1dGVdIC0gYS5fZGF0YVt0aGlzLmlkQXR0cmlidXRlXTtcbiAgICB9LFxuXG4gICAgc29ydDogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLl9tb2RlbHMgPSB0aGlzLl9tb2RlbHMuc29ydCh0aGlzLnNvcnRGbi5iaW5kKHRoaXMpKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzO1xuICAgIH0sXG5cbiAgICBnZXRCeUlkOiBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgcmV0dXJuIF8uZmluZCh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbS5nZXQodGhpcy5pZEF0dHJpYnV0ZSkgPT09IGlkO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgZWFjaDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uZWFjaCh0aGlzLl9tb2RlbHMsIGNiLCBjdHggfHwgdGhpcyk7XG4gICAgfSxcblxuICAgIGFsbDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uYWxsKHRoaXMuX21vZGVscywgY2IsIGN0eCB8fCB0aGlzKTtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBfLmludm9rZSh0aGlzLl9tb2RlbHMsICd0b0pTT04nKTtcbiAgICB9LFxuXG4gICAgZmluZDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbmQodGhpcy5fbW9kZWxzLCBmbik7XG4gICAgfSxcblxuICAgIGZpbHRlcjogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbHRlcih0aGlzLl9tb2RlbHMsIGZuKTtcbiAgICB9LFxuXG4gICAgc2l6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgbWFwOiBmdW5jdGlvbiAoZm4sIGN0eCkge1xuICAgICAgICByZXR1cm4gXy5tYXAodGhpcy5fbW9kZWxzLCBmdW5jdGlvbiAobW9kZWwpIHtcbiAgICAgICAgICAgIHJldHVybiBmbi5jYWxsKGN0eCwgbW9kZWwudG9KU09OKCkpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgcGx1Y2s6IGZ1bmN0aW9uIChmaWVsZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBtW2ZpZWxkXTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlQ29sbGVjdGlvbjsiLCIndXNlIHN0cmljdCc7XG5cblxudmFyIEJhc2VNb2RlbCA9IGZ1bmN0aW9uIChhdHRyLCBvcHRpb25zKSB7XG4gICAgYXR0ciA9IF8uZGVmYXVsdHMoe30sIGF0dHIsIF8ucmVzdWx0KHRoaXMsICdkZWZhdWx0cycpKTtcbiAgICB0aGlzLl9kYXRhID0ge307XG4gICAgdGhpcy5zZXQoYXR0ciwgb3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlTW9kZWwucHJvdG90eXBlLCB7XG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKGF0dHIsIG9wdGlvbnMpIHtcblxuICAgIH0sXG5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbCwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChrZXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWw7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBfLmV4dGVuZCh0aGlzLl9kYXRhLCBhdHRycyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGdldDogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YVtrZXldO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jb2xsZWN0aW9uLnJlbW92ZSh0aGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICB0b0pTT046IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGE7XG4gICAgfSxcblxuICAgIHBpY2s6IGZ1bmN0aW9uIChrZXlzKSB7XG4gICAgICAgIHJldHVybiBfLnBpY2sodGhpcy5fZGF0YSwga2V5cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlTW9kZWw7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZW52ID0ge1xuICAgIGFjY291bnQ6ICcnLFxuICAgIHByb2plY3Q6ICcnLFxuICAgIGdyb3VwOiAnJyxcbiAgICBncm91cElkOiAnJyxcbiAgICB0b2tlbjogJycsXG4gICAgc2VydmVyOiB7XG4gICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgcHJvdG9jb2w6ICdodHRwcydcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBzZXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGVudiA9IF8ubWVyZ2UoZW52LCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBlbnY7XG4gICAgfVxufTsiLCIoZnVuY3Rpb24gKCkge1xuICAgICd1c2Ugc3RyaWN0JztcbiAgICB2YXIgQXBwID0gcmVxdWlyZSgnLi9hc3NpZ25tZW50LmpzJyk7XG5cbiAgICB3aW5kb3cuZm9yaW8gPSB3aW5kb3cuZm9yaW8gfHwge307XG4gICAgd2luZG93LmZvcmlvLk11bHRpcGxheWVyQXNzaWdubWVudENvbXBvbmVudCA9IEFwcDtcbn0pKCk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBzZXJ2aWNlTG9jYXRvciA9IHJlcXVpcmUoJy4vc2VydmljZS1sb2NhdG9yJyk7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG4vLyB2YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBpc0R5bmFtaWNBc3NpZ25tZW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldCgnd29ybGRzJykgPT09ICdkeW5hbWljJztcbiAgICB9LFxuXG4gICAgaGFzUm9sZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJvbGVzID0gdGhpcy5nZXQoJ3JvbGVzJyk7XG4gICAgICAgIHJldHVybiByb2xlcyAmJiAhIXJvbGVzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGFwaSA9IHNlcnZpY2VMb2NhdG9yLndvcmxkQXBpKCk7XG5cbiAgICAgICAgcmV0dXJuIGFwaS5nZXRQcm9qZWN0U2V0dGluZ3MoKS50aGVuKGZ1bmN0aW9uIChzZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5zZXQoc2V0dGluZ3MpO1xuICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cbn0pOyIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVudiA9IHJlcXVpcmUoJy4vZGVmYXVsdHMuanMnKTtcblxudmFyIGNhY2hlID0ge307XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHdvcmxkQXBpOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghY2FjaGUud29ybGRBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLndvcmxkQXBpID0gbmV3IEYuc2VydmljZS5Xb3JsZChlbnYuZ2V0KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLndvcmxkQXBpO1xuICAgIH0sXG5cbiAgICBtZW1iZXJBcGk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFjYWNoZS5tZW1iZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLm1lbWJlckFwaSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKF8ucGljayhlbnYuZ2V0KCksIFsnZ3JvdXBJZCcsICdzZXJ2ZXInXSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLm1lbWJlckFwaTtcbiAgICB9LFxuXG4gICAgdXNlckFwaTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIWNhY2hlLnVzZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLnVzZXJBcGkgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoXy5waWNrKGVudi5nZXQoKSwgWydhY2NvdW50JywgJ3NlcnZlciddKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2FjaGUudXNlckFwaTtcbiAgICB9XG59OyIsImV4cG9ydHNbXCJlZGl0LXVzZXItcm93XCJdID0gZnVuY3Rpb24ob2JqKSB7XG5vYmogfHwgKG9iaiA9IHt9KTtcbnZhciBfX3QsIF9fcCA9ICcnLCBfX2UgPSBfLmVzY2FwZSwgX19qID0gQXJyYXkucHJvdG90eXBlLmpvaW47XG5mdW5jdGlvbiBwcmludCgpIHsgX19wICs9IF9fai5jYWxsKGFyZ3VtZW50cywgJycpIH1cbndpdGggKG9iaikge1xuX19wICs9ICc8dGQ+PGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGNsYXNzPVwic2VsZWN0XCIgZGF0YS1pZD1cIicgK1xuKChfX3QgPSAoIGlkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+PC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cIndvcmxkc1wiIGNsYXNzPVwiZm9ybS1jb250cm9sXCIgZGF0YS1maWVsZD1cIndvcmxkXCI+XFxuXFxuICAgICc7XG4gXy5lYWNoKHdvcmxkcywgZnVuY3Rpb24gKHcpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHcgPT09IHdvcmxkID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIicgK1xuKChfX3QgPSAoIG5ld1dvcmxkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiIGNsYXNzPVwibmV3LXdvcmxkLXRleHRcIj48aT4nICtcbigoX190ID0gKCBuZXdXb3JsZCApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbicgLSBOZXcgLTwvaT48L29wdGlvbj5cXG4gICAgPC9zZWxlY3Q+XFxuPC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cInJvbGVzXCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBkYXRhLWZpZWxkPVwicm9sZVwiPlxcbiAgICAnO1xuIF8uZWFjaChyb2xlcywgZnVuY3Rpb24gKHIpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHIgPT09IHJvbGUgPyAnc2VsZWN0ZWQnIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPicgK1xuKChfX3QgPSAoIHIgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC9vcHRpb24+XFxuICAgICc7XG4gfSk7IDtcbl9fcCArPSAnXFxuXFxuICAgICc7XG4gXy5lYWNoKG9wdGlvbmFsUm9sZXMsIGZ1bmN0aW9uIChyKSB7IDtcbl9fcCArPSAnXFxuICAgICAgICA8b3B0aW9uIHZhbHVlPVwiJyArXG4oKF9fdCA9ICggciApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbidcIiAnICtcbigoX190ID0gKCByID09PSByb2xlID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJyA8aT4oT3B0aW9uYWwpPC9pPjwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICA8L3NlbGVjdD5cXG48L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi10b29scyBidG4tc2F2ZSBzYXZlXCI+U2F2ZTwvYnV0dG9uPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi10b29scyBidG4tY2FuY2VsIGNhbmNlbFwiPkNhbmNlbDwvYnV0dG9uPlxcbjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTtcbmV4cG9ydHNbXCJ1c2VyLXJvd1wiXSA9IGZ1bmN0aW9uKG9iaikge1xub2JqIHx8IChvYmogPSB7fSk7XG52YXIgX190LCBfX3AgPSAnJywgX19lID0gXy5lc2NhcGU7XG53aXRoIChvYmopIHtcbl9fcCArPSAnPHRkPjxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cInNlbGVjdFwiIGRhdGEtaWQ9XCInICtcbigoX190ID0gKCBpZCkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggIWlzV29ybGRDb21wbGV0ZSA/ICc8ZW0gY2xhc3M9XCJmLWljb24gZi13YXJuaW5nXCI+PC9lbT4nIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggd29ybGQgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggcm9sZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPjxidXR0b24gY2xhc3M9XCJidG4gZWRpdCBidG4tZWRpdCBidG4tdG9vbHMgYXV0by1oaWRlXCI+RWRpdDwvYnV0dG9uPjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBkZWZhdWx0czoge1xuICAgICAgICB3b3JsZDogJycsXG4gICAgICAgIHJvbGU6ICcnLFxuICAgICAgICBhY3RpdmU6IHRydWUsXG4gICAgICAgIGlzV29ybGRDb21wbGV0ZTogdHJ1ZSxcbiAgICAgICAgZmlyc3ROYW1lOiAnJyxcbiAgICAgICAgbGFzdE5hbWU6ICcnXG4gICAgfSxcblxuICAgIG1ha2VBY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gbWVtYmVyQXBpLm1ha2VVc2VyQWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBtYWtlSW5hY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBmYWxzZSk7XG5cbiAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5tYWtlVXNlckluYWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cblxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcblxudmFyIE1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcblxuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBtb2RlbDogTW9kZWwsXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHZhciBhdyA9IGEuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBidyA9IGIuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIGlmIChhdyAhPT0gYncpIHtcbiAgICAgICAgICAgIHJldHVybiBhdyA8IGJ3ID8gLTEgOiAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGIuZ2V0KCd1c2VyTmFtZScpID4gYS5nZXQoJ3VzZXJOYW1lJykgPyAtMSA6IDE7XG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJC5hamF4U2V0dXAoe1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIGVudi5nZXQoKS50b2tlblxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgYWxsVXNlcnNBc3NpZ25lZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hbGwoZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiAhIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0VW5hc3NpZ25lZFVzZXJzQ291bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmlsdGVyKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICByZXR1cm4gIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KS5sZW5ndGg7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBncm91cElkID0gZW52LmdldCgpLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGdldEdyb3VwVXNlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbWVtYmVyQXBpID0gc2VydmljZUxvY2F0b3IubWVtYmVyQXBpKCk7XG4gICAgICAgICAgICB2YXIgdXNlckFwaSA9IHNlcnZpY2VMb2NhdG9yLnVzZXJBcGkoKTtcblxuICAgICAgICAgICAgdmFyIGxvYWRHcm91cE1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5nZXRHcm91cERldGFpbHMoKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBsb2FkVXNlcnNJbmZvID0gZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vbkZhY0FuZEFjdGl2ZSA9IGZ1bmN0aW9uICh1KSB7IHJldHVybiB1LmFjdGl2ZSAmJiB1LnJvbGUgIT09ICdmYWNpbGl0YXRvcic7IH07XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJzID0gXy5wbHVjayhfLmZpbHRlcihncm91cC5tZW1iZXJzLCBub25GYWNBbmRBY3RpdmUpLCAndXNlcklkJyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVzZXJBcGkuZ2V0KHsgaWQ6IHVzZXJzIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGxvYWRHcm91cE1lbWJlcnMoKVxuICAgICAgICAgICAgICAgIC50aGVuKGxvYWRVc2Vyc0luZm8pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgZ2V0R3JvdXBVc2VycygpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAodXNlcnMpIHtcbiAgICAgICAgICAgICAgICB1c2VycyA9IF8ubWFwKHVzZXJzLCBmdW5jdGlvbiAodSkgeyByZXR1cm4gXy5leHRlbmQodSwgeyBncm91cElkOiBncm91cElkIH0pOyB9KTtcbiAgICAgICAgICAgICAgICBfdGhpcy5zZXQodXNlcnMpO1xuICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHVzZXJzLCBfdGhpcyk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9XG5cbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBkZWZhdWx0czoge1xuICAgICAgICB1c2VyczogbnVsbCxcbiAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX19zdXBlci5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgdGhpcy5fZGF0YS51c2VycyA9IHRoaXMuX2RhdGEudXNlcnMgfHwgW107XG5cbiAgICAgICAgdGhpcy5fd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuXG4gICAgICAgIHZhciBpZCA9IHRoaXMuZ2V0KCdpZCcpO1xuICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgYWRkVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIHVzZXJzLnB1c2godXNlcik7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuc2F2ZSgpO1xuICAgIH0sXG5cbiAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlcikge1xuICAgICAgICB2YXIgaWQgPSB0aGlzLmdldCgnaWQnKTtcbiAgICAgICAgdmFyIGNoZWNrV29ybGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuZ2V0KCd1c2VycycpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSkuZGVsZXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICBfLnJlbW92ZSh0aGlzLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiB1LmdldCgnaWQnKSA9PT0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl93b3JsZEFwaVxuICAgICAgICAgICAgLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSlcbiAgICAgICAgICAgIC5yZW1vdmVVc2VyKHsgdXNlcklkOiB1c2VyLmdldCgnaWQnKSB9KVxuICAgICAgICAgICAgLnRoZW4oY2hlY2tXb3JsZCk7XG4gICAgfSxcblxuICAgIHNhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIG1hcFVzZXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIF8ubWFwKHRoaXMuZ2V0KCd1c2VycycpLCBmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgICAgIHZhciByZXMgPSB7IHVzZXJJZDogdS5nZXQoJ2lkJykgfTtcbiAgICAgICAgICAgICAgICB2YXIgcm9sZSA9IHUuZ2V0KCdyb2xlJyk7XG5cbiAgICAgICAgICAgICAgICBpZiAocm9sZSkge1xuICAgICAgICAgICAgICAgICAgICByZXMucm9sZSA9IHJvbGU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIGNyZWF0ZVdvcmxkID0gXy5wYXJ0aWFsKHRoaXMuX3dvcmxkQXBpLmNyZWF0ZSwgdGhpcy5waWNrKFsnbW9kZWwnLCAnbmFtZScsICdtaW5Vc2VycyddKSk7XG4gICAgICAgIHZhciBhZGRVc2VycyA9IF8ucGFydGlhbChfdGhpcy5fd29ybGRBcGkuYWRkVXNlcnMsIG1hcFVzZXJzKCksIHsgZmlsdGVyOiBfdGhpcy5nZXQoJ2lkJykgfSk7XG4gICAgICAgIHZhciBzYXZlZFVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIGlmICh0aGlzLmlzTmV3KCkpIHtcbiAgICAgICAgICAgIC8vIHdlIG5lZWQgdG8gY3JlYXRlIHRoZSB3b3JsZCBpbiB0aGUgQVBJIGFuZCB0aGVuIGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVXb3JsZCgpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNldCh3b3JsZCk7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLl93b3JsZEFwaS51cGRhdGVDb25maWcoeyBmaWx0ZXI6IHdvcmxkLmlkIH0pO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oYWRkVXNlcnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHVzZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHNpbmNlIHdlIHJlLXNldCB0aGUgd29ybGQsIHJlLXNldCB0aGUgdXNlcnNcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuc2V0KCd1c2VycycsIHNhdmVkVXNlcnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gdGhlIHdvcmxkIGlzIGFscmVhZHkgY3JlYXRlZCBqdXN0IGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBhZGRVc2VycygpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGlzTmV3OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5nZXQoJ2xhc3RNb2RpZmllZCcpO1xuICAgIH1cblxufSk7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgTW9kZWwgPSByZXF1aXJlKCcuL3dvcmxkLW1vZGVsJyk7XG52YXIgVXNlck1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG52YXIgZG9uZUZuID0gZnVuY3Rpb24gKGR0ZCwgYWZ0ZXIpIHtcbiAgICByZXR1cm4gXy5hZnRlcihhZnRlciwgZHRkLnJlc29sdmUpO1xufTtcblxudmFyIHdvcmxkQXBpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgbW9kZWw6IE1vZGVsLFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBfX3N1cGVyLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuICAgIH0sXG5cbiAgICBhdXRvQXNzaWduQWxsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gd29ybGRBcGkuYXV0b0Fzc2lnbihvcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzZXQodGhpcy5wYXJzZSh3b3JsZHMpKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGdldEluY29tcGxldGVXb3JsZHNDb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24gKHcpIHtcbiAgICAgICAgICAgIHJldHVybiAhdy5nZXQoJ2NvbXBsZXRlJyk7XG4gICAgICAgIH0pLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgdXBkYXRlVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHdvcmxkTmFtZSA9IHVzZXIuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgcHJldldvcmxkID0gdGhpcy5nZXRXb3JsZEJ5VXNlcih1c2VyKTtcbiAgICAgICAgdmFyIGN1cldvcmxkID0gdGhpcy5nZXRPckNyZWF0ZVdvcmxkKHdvcmxkTmFtZSk7XG4gICAgICAgIHZhciBkb25lID0gZG9uZUZuKGR0ZCwgMSk7XG5cbiAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUncyBhbnl0aGluZyB0byBkb1xuICAgICAgICBpZiAoIXByZXZXb3JsZCAmJiAhY3VyV29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiBkdGQucmVzb2x2ZSgpLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwcmV2V29ybGQpIHtcbiAgICAgICAgICAgIHByZXZXb3JsZC5yZW1vdmVVc2VyKHVzZXIpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY3VyV29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjdXJXb3JsZC5hZGRVc2VyKHVzZXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAudGhlbihkb25lKTtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJXb3JsZCkge1xuICAgICAgICAgICAgY3VyV29ybGQuYWRkVXNlcih1c2VyKVxuICAgICAgICAgICAgICAgIC50aGVuKGRvbmUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldE9yQ3JlYXRlV29ybGQ6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgaWYgKCF3b3JsZE5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB3b3JsZCA9IHRoaXMuZ2V0V29yZEJ5TmFtZSh3b3JsZE5hbWUpO1xuXG4gICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgIHdvcmxkID0gdGhpcy5jcmVhdGUoeyBuYW1lOiB3b3JsZE5hbWUgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gd29ybGQ7XG4gICAgfSxcblxuICAgIGdldFdvcmRCeU5hbWU6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmluZChmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiB3b3JsZC5nZXQoJ25hbWUnKSA9PT0gd29ybGROYW1lO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGRCeVVzZXI6IGZ1bmN0aW9uICh1c2VyKSB7XG4gICAgICAgIGlmICghdXNlci5nZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZ2V0V29ybGRCeVVzZXIgZXhwZWN0ZXMgYSBtb2RlbCAoJyArIHVzZXIgKyAnKScpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGlkID0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFdvcmxkQnlVc2VySWQoaWQpO1xuICAgIH0sXG5cbiAgICBnZXRXb3JsZEJ5VXNlcklkOiBmdW5jdGlvbiAodXNlcklkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZpbmQoZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICByZXR1cm4gXy5maW5kKHdvcmxkLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdS5nZXQoJ2lkJykgPT09IHVzZXJJZDtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGROYW1lczogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wbHVjaygnbmFtZScpO1xuICAgIH0sXG5cbiAgICBnZXROZXh0V29ybGROYW1lOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBwYWQgPSBmdW5jdGlvbiAobnVtLCBwbGFjZXMpIHtcbiAgICAgICAgICAgIHZhciB6ZXJvcyA9ICcwMDAwMDAwMDAwMDAwMDAwMDAnO1xuICAgICAgICAgICAgdmFyIGRpZ2l0cyA9IG51bS50b1N0cmluZygpLmxlbmd0aDtcbiAgICAgICAgICAgIHZhciBuZWVkZWQgPSBwbGFjZXMgLSBkaWdpdHM7XG4gICAgICAgICAgICByZXR1cm4gemVyb3Muc3Vic3RyKDAsIG5lZWRlZCkgKyBudW07XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHdvcmxkcyA9IHRoaXMuZ2V0V29ybGROYW1lcygpO1xuXG4gICAgICAgIGlmICghd29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuICdXb3JsZDAwMSc7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcHJvcGVyTmFtZXMgPSBfLmZpbHRlcih3b3JsZHMsIGZ1bmN0aW9uICh3KSB7IHJldHVybiAvV29ybGRcXGRcXGRcXGQvLnRlc3Qodyk7IH0pLnNvcnQoKTtcbiAgICAgICAgdmFyIGxhc3RXb3JsZCA9IHByb3Blck5hbWVzW3Byb3Blck5hbWVzLmxlbmd0aCAtIDFdO1xuICAgICAgICB2YXIgbnVtV29ybGQgPSArbGFzdFdvcmxkLm1hdGNoKC9Xb3JsZChcXGRcXGRcXGQpLylbMV07XG4gICAgICAgIHJldHVybiAnV29ybGQnICsgcGFkKG51bVdvcmxkICsgMSwgMyk7XG4gICAgfSxcblxuICAgIHNldFVzZXJzQ29sbGVjdGlvbjogZnVuY3Rpb24gKHVzZXJzQ29sbGVjdGlvbikge1xuICAgICAgICB0aGlzLnVzZXJzQ29sbGVjdGlvbiA9IHVzZXJzQ29sbGVjdGlvbjtcbiAgICB9LFxuXG4gICAgam9pblVzZXJzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1c2Vyc0hhc2ggPSB7fTtcbiAgICAgICAgdmFyIHVzZXJzQ29sbGVjdGlvbiA9IHRoaXMudXNlcnNDb2xsZWN0aW9uO1xuICAgICAgICB1c2Vyc0NvbGxlY3Rpb24uZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdS5zZXQoeyBpc1dvcmxkQ29tcGxldGU6IHRydWUgfSk7XG4gICAgICAgICAgICByZXR1cm4gKHVzZXJzSGFzaFt1LmdldCgnaWQnKV0gPSB1KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5lYWNoKGZ1bmN0aW9uICh3LCBpKSB7XG4gICAgICAgICAgICB2YXIgbmFtZSA9IHcuZ2V0KCduYW1lJyk7XG4gICAgICAgICAgICB2YXIgaXNDb21wbGV0ZSA9IHcuZ2V0KCdjb21wbGV0ZScpO1xuICAgICAgICAgICAgdy5zZXQoeyBpbmRleDogaSwgbmFtZTogbmFtZSB8fCAoaSArIDEpICsgJycgfSk7XG4gICAgICAgICAgICBfLmVhY2gody5nZXQoJ3VzZXJzJyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgaWYgKHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldKSB7XG4gICAgICAgICAgICAgICAgICAgIHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldLnNldCh7IHdvcmxkOiBuYW1lLCByb2xlOiB1LmdldCgncm9sZScpLCBpc1dvcmxkQ29tcGxldGU6IGlzQ29tcGxldGUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHVzZXJzQ29sbGVjdGlvbi5zb3J0KCk7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB3b3JsZEFwaS5saXN0KClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc2V0KHRoaXMucGFyc2Uod29ybGRzKSk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBwYXJzZTogZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICBpZiAod29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgd29ybGRzID0gXy5tYXAod29ybGRzLCBmdW5jdGlvbiAodykge1xuICAgICAgICAgICAgICAgIHZhciB1c2VycyA9IF8ubWFwKHcudXNlcnMsIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGluIHRoZSB3b3JsZCBhcGkgdXNlcnMgSWRzIGNvbWVzIGFzIHVzZXJJZFxuICAgICAgICAgICAgICAgICAgICAvLyBtYWtlIHN1cmUgd2UgYWRkIGl0IGFzIGlkIHNvIHdlIGNhbiB1c2UgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIHNhbWUgY29kZSB0byBhY2Nlc3MgbW9kZWxzIHRoYXQgY29tZSBmcm9tIHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyBtZW1iZXIvbG9jYWwgYXBpIGFzIHdpdGggdGhlIHdvcmxkIGFwaVxuICAgICAgICAgICAgICAgICAgICB1LmlkID0gdS51c2VySWQ7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVXNlck1vZGVsKHUpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgdy51c2VycyA9IHVzZXJzO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHc7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB3b3JsZHM7XG4gICAgfVxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuKiBVdGlsaXR5IGNsYXNzIHRvIG1ha2UgYWpheCBjYWxscyBzZXF1ZW5jaWFsXG4qL1xuZnVuY3Rpb24gQWpheFF1ZXVlICgpIHtcbiAgICB0aGlzLnF1ZXVlID0gW107XG59XG5cbiQuZXh0ZW5kKEFqYXhRdWV1ZS5wcm90b3R5cGUsIHtcbiAgICBhZGQ6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICByZXR1cm4gdGhpcy5xdWV1ZS5wdXNoKGZuKTtcbiAgICB9LFxuXG4gICAgZXhlY3V0ZTogZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgY29udGV4dCA9IGNvbnRleHQgfHwgdGhpcztcblxuICAgICAgICBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgICAgICAgaWYgKF90aGlzLnF1ZXVlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBmbiA9IF90aGlzLnF1ZXVlLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgICAgICBmbi5jYWxsKGNvbnRleHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKG5leHQpXG4gICAgICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbmV4dCgpO1xuXG4gICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQWpheFF1ZXVlOyIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiJdfQ== +//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Fzc2lnbm1lbnQtcm93LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9hc3NpZ25tZW50LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9iYXNlLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Jhc2UtbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2RlZmF1bHRzLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9pbmRleC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvcHJvamVjdC1tb2RlbC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvc2VydmljZS1sb2NhdG9yLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy90ZW1wbGF0ZXMuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXItbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXJzLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3dvcmxkLW1vZGVsLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy93b3JsZHMtY29sbGVjdGlvbi5qcyIsInNyYy91dGlsL2FqYXgtcXVldWUuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCc7XG5cbnZhciB0ZW1wbGF0ZXMgPSByZXF1aXJlKCcuL3RlbXBsYXRlcycpO1xuXG52YXIgQXNzaWdubWVudFJvdyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy4kZWwgPSAkKCc8dHI+Jyk7XG4gICAgdGhpcy5lbCA9IHRoaXMuJGVsWzBdO1xuICAgIHRoaXMuJCA9IF8ucGFydGlhbFJpZ2h0KCQsIHRoaXMuJGVsKTtcblxuICAgIHRoaXMubW9kZWwgPSBvcHRpb25zLm1vZGVsO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy53b3JsZHMgPSBvcHRpb25zLndvcmxkcztcbiAgICB0aGlzLnByb2plY3QgPSBvcHRpb25zLnByb2plY3Q7XG5cbiAgICBfLmJpbmRBbGwodGhpcywgWydzZXRFZGl0TW9kZScsICdyZW1vdmVFZGl0TW9kZScsICdzYXZlRWRpdCcsICdjYW5jZWxFZGl0JywgJ3VwZGF0ZURhdGEnXSk7XG5cbiAgICB0aGlzLmJpbmRFdmVudHMoKTtcblxufTtcblxuXy5leHRlbmQoQXNzaWdubWVudFJvdy5wcm90b3R5cGUsIHtcblxuICAgIHRlbXBsYXRlOiB0ZW1wbGF0ZXNbJ3VzZXItcm93J10sXG5cbiAgICBlZGl0VGVtcGxhdGU6IHRlbXBsYXRlc1snZWRpdC11c2VyLXJvdyddLFxuXG4gICAgYmluZEV2ZW50czogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnYnV0dG9uLmVkaXQnLCB0aGlzLnNldEVkaXRNb2RlKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2J1dHRvbi5zYXZlJywgdGhpcy5zYXZlRWRpdCk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICdidXR0b24uY2FuY2VsJywgdGhpcy5jYW5jZWxFZGl0KTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9mZignY2xpY2snLCBudWxsLCBudWxsKTtcbiAgICAgICAgLy8gdGhpcyBvbmx5IGdpdmVzIGEgZGVsYXkgdG8gcmVtb3ZlIHRoZSB0clxuICAgICAgICAvLyBhbmltYXRpb24gb2YgaGVpZ2h0IG9mIHRoZSB0ciBkb2VzIG5vdCB3b3JrXG4gICAgICAgIHRoaXMuJCgnOmNoZWNrYm94JykuYXR0cignY2hlY2tlZCcsIGZhbHNlKTtcbiAgICAgICAgdGhpcy4kZWxcbiAgICAgICAgICAgIC5jc3MoeyBvcGFjaXR5OiAwLjMgfSlcbiAgICAgICAgICAgIC5hbmltYXRlKHsgaGVpZ2h0OiAwIH0sIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMzAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIG1ha2VJbmFjdGl2ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tb2RlbC5tYWtlSW5hY3RpdmUoKTtcbiAgICB9LFxuXG4gICAgc2V0RWRpdE1vZGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5tb2RlbC5zZXQoJ2VkaXQtbW9kZScsIHRydWUpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICByZW1vdmVFZGl0TW9kZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLm1vZGVsLnNldCgnZWRpdC1tb2RlJywgZmFsc2UpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICBzYXZlRWRpdDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB0aGlzLnVwZGF0ZURhdGEoKTtcbiAgICAgICAgdGhpcy53b3JsZHNcbiAgICAgICAgICAgIC51cGRhdGVVc2VyKHRoaXMubW9kZWwpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMucmVtb3ZlRWRpdE1vZGUoKTtcbiAgICAgICAgICAgICAgICBfdGhpcy4kZWwudHJpZ2dlcigndXBkYXRlJywgX3RoaXMpO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGNhbmNlbEVkaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVFZGl0TW9kZSgpO1xuICAgIH0sXG5cbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHRlbXBsID0gdGhpcy5tb2RlbC5nZXQoJ2VkaXQtbW9kZScpID8gdGhpcy5lZGl0VGVtcGxhdGUgOiB0aGlzLnRlbXBsYXRlO1xuICAgICAgICB2YXIgdm0gPSBfLmV4dGVuZCh7XG4gICAgICAgICAgICByb2xlczogdGhpcy5wcm9qZWN0LmdldCgncm9sZXMnKSxcbiAgICAgICAgICAgIG9wdGlvbmFsUm9sZXM6IHRoaXMucHJvamVjdC5nZXQoJ29wdGlvbmFsUm9sZXMnKSxcbiAgICAgICAgICAgIHdvcmxkczogdGhpcy53b3JsZHMuZ2V0V29ybGROYW1lcygpLFxuICAgICAgICAgICAgbmV3V29ybGQ6IHRoaXMud29ybGRzLmdldE5leHRXb3JsZE5hbWUoKVxuICAgICAgICB9LCB0aGlzLm1vZGVsLnRvSlNPTigpKTtcblxuICAgICAgICB0aGlzLiRlbC5odG1sKHRlbXBsKHZtKSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIHVwZGF0ZURhdGE6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdGhpcy4kKCdbZGF0YS1maWVsZF0nKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBlbCA9ICQodGhpcyk7XG4gICAgICAgICAgICB2YXIgZmllbGQgPSBlbC5kYXRhKCdmaWVsZCcpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IGVsLnZhbCgpO1xuXG4gICAgICAgICAgICBfdGhpcy5tb2RlbC5zZXQoZmllbGQsIHZhbCk7XG4gICAgICAgIH0pO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQXNzaWdubWVudFJvdzsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBVc2Vyc0NvbGxlY3Rpb24gPSByZXF1aXJlKCcuL3VzZXJzLWNvbGxlY3Rpb24nKTtcbnZhciBXb3JsZHNDb2xsZWN0aW9uID0gcmVxdWlyZSgnLi93b3JsZHMtY29sbGVjdGlvbicpO1xudmFyIFByb2plY3RNb2RlbCA9IHJlcXVpcmUoJy4vcHJvamVjdC1tb2RlbCcpO1xudmFyIEFzc2lnbmVtbnRSb3cgPSByZXF1aXJlKCcuL2Fzc2lnbm1lbnQtcm93Jyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIEFqYXhRdWV1ZSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvYWpheC1xdWV1ZScpO1xuXG5mdW5jdGlvbiBzZXRFbnZpcm9ubWVudChvcHRpb25zKSB7XG4gICAgZW52LnNldChfLm9taXQob3B0aW9ucywgJ2VsJykpO1xufVxuXG52YXIgQXNzaWdubWVudCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgc2V0RW52aXJvbm1lbnQob3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplKG9wdGlvbnMpO1xufTtcblxuQXNzaWdubWVudC5wcm90b3R5cGUgPSB7XG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLmVsID0gdHlwZW9mIG9wdGlvbnMuZWwgPT09ICdzdHJpbmcnID8gJChvcHRpb25zLmVsKVswXSA6IG9wdGlvbnMuZWw7XG4gICAgICAgIHRoaXMuJGVsID0gJCh0aGlzLmVsKTtcbiAgICAgICAgdGhpcy4kID0gXy5wYXJ0aWFsUmlnaHQoJCwgdGhpcy5lbCk7XG5cbiAgICAgICAgdGhpcy51c2VycyA9IG5ldyBVc2Vyc0NvbGxlY3Rpb24oKTtcbiAgICAgICAgdGhpcy53b3JsZHMgPSBuZXcgV29ybGRzQ29sbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnByb2plY3QgPSBuZXcgUHJvamVjdE1vZGVsKCk7XG5cbiAgICAgICAgXy5iaW5kQWxsKHRoaXMsIFsncmVuZGVyJywgJ3JlbmRlclRhYmxlJywgJ3RvZ2dsZUNvbnRyb2xscycsICdzYXZlRWRpdCcsICdzZWxlY3RBbGwnLCAndXNhc3NpZ25TZWxlY3RlZCcsICdfc2hvd1VwZGF0aW5nJywgJ19oaWRlVXBkYXRpbmcnLCAnYXV0b0Fzc2lnbkFsbCcsICdtYWtlVXNlckluYWN0aXZlJ10pO1xuXG4gICAgICAgIHRoaXMuYmluZEV2ZW50cygpO1xuICAgIH0sXG5cbiAgICBiaW5kRXZlbnRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9uKCd1cGRhdGUnLCAndHInLCB0aGlzLnNhdmVFZGl0KTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2lucHV0OmNoZWNrYm94Om5vdCgjc2VsZWN0LWFsbCknLCB0aGlzLnRvZ2dsZUNvbnRyb2xscyk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICcjc2VsZWN0LWFsbCcsIHRoaXMuc2VsZWN0QWxsKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy51bmFzc2lnbi11c2VyJywgdGhpcy51c2Fzc2lnblNlbGVjdGVkKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy5hdXRvLWFzc2lnbi1hbGwnLCB0aGlzLmF1dG9Bc3NpZ25BbGwpO1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnLm1ha2UtdXNlci1pbmFjdGl2ZScsIHRoaXMubWFrZVVzZXJJbmFjdGl2ZSk7XG4gICAgfSxcblxuICAgIGxvYWQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB2YXIgam9pbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLnNldFVzZXJzQ29sbGVjdGlvbih0aGlzLnVzZXJzKTtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLmpvaW5Vc2VycygpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHJldHVybiAkLndoZW4oXG4gICAgICAgICAgICB0aGlzLndvcmxkcy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy51c2Vycy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy5wcm9qZWN0LmZldGNoKClcbiAgICAgICAgKS50aGVuKGpvaW4pO1xuXG4gICAgfSxcblxuICAgIHNhdmVFZGl0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMud29ybGRzLmZldGNoKClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ29udHJvbHMoKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGF1dG9Bc3NpZ25BbGw6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG4gICAgICAgIHZhciBtYXhVc2VycyA9ICt0aGlzLiQoJyNtYXgtdXNlcnMnKS52YWwoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMud29ybGRzLmF1dG9Bc3NpZ25BbGwoeyBtYXhVc2VyczogbWF4VXNlcnMgfSlcbiAgICAgICAgICAgIC5kb25lKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC5mYWlsKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9LFxuXG4gICAgZ2V0U2VsZWN0ZWRJZHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuJCgndGJvZHkgOmNoZWNrYm94OmNoZWNrZWQnKS5tYXAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICQodGhpcykuZGF0YSgnaWQnKTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGZpbmRSb3dWaWV3czogZnVuY3Rpb24gKGlkcykge1xuICAgICAgICByZXR1cm4gXy5tYXAoaWRzLCBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJvd1ZpZXdzW2lkXTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfSxcblxuICAgIHVuYXNzaWduVXNlcnM6IGZ1bmN0aW9uIChpZHMpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIGZvciBub3cgd2UgbmVlZCB0byBzZXF1ZW5jZSB0aGUgY2FsbHMgdG8gdW5hc3NpZ24gdXNlcnMgZnJvbSB3b3JsZHNcbiAgICAgICAgdmFyIHF1ZXVlID0gbmV3IEFqYXhRdWV1ZSgpO1xuXG4gICAgICAgIF8uZWFjaChpZHMsIGZ1bmN0aW9uICh1c2VySWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyID0gdGhpcy51c2Vycy5nZXRCeUlkKHVzZXJJZCk7XG4gICAgICAgICAgICB1c2VyLnNldCgnd29ybGQnLCAnJyk7XG4gICAgICAgICAgICB1c2VyLnNldCgncm9sZScsICcnKTtcbiAgICAgICAgICAgIHF1ZXVlLmFkZChfLnBhcnRpYWwoXy5iaW5kKHRoaXMud29ybGRzLnVwZGF0ZVVzZXIsIHRoaXMud29ybGRzKSwgdXNlcikpO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIHVzYXNzaWduU2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICB2YXIgaWRzID0gdGhpcy5nZXRTZWxlY3RlZElkcygpO1xuXG4gICAgICAgIHZhciBkb25lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy53b3JsZHMuZmV0Y2goKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9oaWRlVXBkYXRpbmcoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudW5hc3NpZ25Vc2VycyhpZHMpLnRoZW4oZG9uZSk7XG4gICAgfSxcblxuICAgIG1ha2VVc2VySW5hY3RpdmU6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdmFyIGlkcyA9IHRoaXMuZ2V0U2VsZWN0ZWRJZHMoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIG1ha2VVc2Vyc0luYWN0aXZlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJvd3MgPSB0aGlzLmZpbmRSb3dWaWV3cyhpZHMpO1xuICAgICAgICAgICAgLy8gZm9yIG5vdyB3ZSBuZWVkIHRvIHNlcXVlbmNlIHRoZSBjYWxscyB0byBwYXRjaCB0aGUgdXNlcnNcbiAgICAgICAgICAgIC8vIHNpbmNlIHRoZSBBUEkgY2FuIG9ubHkgb3BlcmF0ZSBvbiBvbmUgY2FsbCBwZXIgZ3JvdXAgYXQgYSB0aW1lXG4gICAgICAgICAgICB2YXIgcXVldWUgPSBuZXcgQWpheFF1ZXVlKCk7XG4gICAgICAgICAgICBfLmVhY2gocm93cywgZnVuY3Rpb24gKHZpZXcpIHtcbiAgICAgICAgICAgICAgICB2YXIgdXNlciA9IHZpZXcubW9kZWw7XG4gICAgICAgICAgICAgICAgcXVldWUuYWRkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZpZXcubWFrZUluYWN0aXZlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZXcucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gdGhpcy51bmFzc2lnblVzZXJzKGlkcylcbiAgICAgICAgICAgIC50aGVuKG1ha2VVc2Vyc0luYWN0aXZlKTtcblxuXG4gICAgfSxcblxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiQoJ3RhYmxlIHRib2R5JykuZW1wdHkoKTtcbiAgICAgICAgdGhpcy5yZW5kZXJUYWJsZSgpO1xuICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgIH0sXG5cbiAgICByZW5kZXJUYWJsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJvd1ZpZXdzID0ge307XG4gICAgICAgIHZhciByb3dzID0gW107XG4gICAgICAgIHRoaXMudXNlcnMuZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgQXNzaWduZW1udFJvdyh7IG1vZGVsOiB1LCB3b3JsZHM6IHRoaXMud29ybGRzLCBwcm9qZWN0OiB0aGlzLnByb2plY3QgfSk7XG4gICAgICAgICAgICB0aGlzLnJvd1ZpZXdzW3UuZ2V0KCdpZCcpXSA9IHZpZXc7XG4gICAgICAgICAgICByb3dzLnB1c2godmlldy5yZW5kZXIoKS5lbCk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHRoaXMuJCgndGFibGUgdGJvZHknKS5hcHBlbmQocm93cyk7XG4gICAgfSxcblxuXG4gICAgdXBkYXRlQ29udHJvbHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9sc0ZvclNlbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnVwZGF0ZUF1dG9Bc3NpZ25CdXR0b24oKTtcbiAgICAgICAgdGhpcy51cGRhdGVTdGF0dXMoKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlU3RhdHVzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbmNvbHBsZXRlV29ybGRzID0gdGhpcy53b3JsZHMuZ2V0SW5jb21wbGV0ZVdvcmxkc0NvdW50KCk7XG4gICAgICAgIHZhciB1bmFzc2lnbmVkVXNlcnMgPSB0aGlzLnVzZXJzLmdldFVuYXNzaWduZWRVc2Vyc0NvdW50KCk7XG4gICAgICAgIHZhciB0b3RhbFdvcmxkcyA9IHRoaXMud29ybGRzLnNpemUoKTtcblxuICAgICAgICB2YXIgdXNlcnNUZXh0ID0gdW5hc3NpZ25lZFVzZXJzID8gdW5hc3NpZ25lZFVzZXJzID09PSAxID8gJzEgdXNlciBuZWVkcyBhc3NpZ25tZW50LicgOiB1bmFzc2lnbmVkVXNlcnMgKyAnIHVzZXJzIG5lZWQgYXNzaWdubWVudC4nIDogJ0FsbCB1c2VycyBoYXZlIGJlZW4gYXNzaWduZWQuJztcbiAgICAgICAgdmFyIHdvcmxkc1RleHQgPSAhdG90YWxXb3JsZHMgPyAnTm8gd29ybGRzIGhhdmUgYmVlbiBjcmVhdGVkLicgOiAhaW5jb2xwbGV0ZVdvcmxkcyA/ICdBbGwgd29ybGRzIGFyZSBjb21wbGV0ZS4nIDogaW5jb2xwbGV0ZVdvcmxkcyA9PT0gMSA/ICcxIGluY29tcGxldGUgd29ybGQgbmVlZHMgYXR0ZW50aW9uLicgOiBpbmNvbHBsZXRlV29ybGRzICsgJyBpbmNvbXBsZXRlIHdvcmxkcyBuZWVkIGF0dGVudGlvbi4nO1xuXG4gICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cyAudGV4dCcpLnRleHQodXNlcnNUZXh0KTtcbiAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cyAudGV4dCcpLnRleHQod29ybGRzVGV4dCk7XG5cbiAgICAgICAgaWYgKHVuYXNzaWduZWRVc2Vycykge1xuICAgICAgICAgICAgdGhpcy4kKCcjdXNlcnMtc3RhdHVzJykuYWRkQ2xhc3MoJ2luY29tcGxldGUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5jb2xwbGV0ZVdvcmxkcyB8fCAhdG90YWxXb3JsZHMpIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3dvcmxkcy1zdGF0dXMnKS5hZGRDbGFzcygnaW5jb21wbGV0ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLiQoJy5zdGF0dXMtd2lkZ2V0JykuYWRkQ2xhc3MoJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQ29udHJvbHNGb3JTZWxlY3Rpb246IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG51bVNlbGVjdGVkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpLmxlbmd0aDtcbiAgICAgICAgdGhpcy4kKCcuY29tcG9uZW50LmNvbnRyb2xzJylbbnVtU2VsZWN0ZWQgPyAnYWRkQ2xhc3MnIDogJ3JlbW92ZUNsYXNzJ10oJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQXV0b0Fzc2lnbkJ1dHRvbjogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIGlmICh0aGlzLnByb2plY3QuaXNEeW5hbWljQXNzaWdubWVudCgpKSB7XG4gICAgICAgICAgICB2YXIgaGFzUm9sZXMgPSB0aGlzLnByb2plY3QuaGFzUm9sZXMoKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5zaW5nbGUnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYycpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5keW5hbWljLW5vLXJvbGVzLXRleHQnKVtoYXNSb2xlcyA/ICdoaWRlJyA6ICdzaG93J10oKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpW2hhc1JvbGVzID8gJ2hpZGUnIDogJ3Nob3cnXSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLmR5bmFtaWMnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYy1uby1yb2xlcy10ZXh0JykuaGlkZSgpO1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLnNpbmdsZScpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpLnNob3coKTtcblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudXNlcnMuYWxsVXNlcnNBc3NpZ25lZCgpKSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLnJlbW92ZUNsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLmFkZENsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc2VsZWN0QWxsOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICB0aGlzLiQoJ3Rib2R5IDpjaGVja2JveCcpLnByb3AoJ2NoZWNrZWQnLCBlLnRhcmdldC5jaGVja2VkKTtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICB0b2dnbGVDb250cm9sbHM6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB0b3RhbCA9IHRoaXMuJCgndGJvZHkgOmNoZWNrYm94Jyk7XG4gICAgICAgIHZhciBjaGVja2VkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpO1xuXG4gICAgICAgIGlmICh0b3RhbC5sZW5ndGggPT09IGNoZWNrZWQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykuYXR0cignY2hlY2tlZCcsICdjaGVja2VkJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykucmVtb3ZlQXR0cignY2hlY2tlZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICBfc2hvd1VwZGF0aW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLmNzcyh7IG9wYWNpdHk6IDAuNCB9KTtcbiAgICB9LFxuXG4gICAgX2hpZGVVcGRhdGluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5jc3MoeyBvcGFjaXR5OiAxIH0pO1xuICAgIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBc3NpZ25tZW50OyIsIid1c2Ugc3RyaWN0JztcblxudmFyIEJhc2VDb2xsZWN0aW9uID0gZnVuY3Rpb24gKG1vZGVscywgb3B0aW9ucykge1xuICAgIHRoaXMuX21vZGVscyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlQ29sbGVjdGlvbi5wcm90b3R5cGUsIHtcbiAgICBpZEF0dHJpYnV0ZTogJ2lkJyxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uIChtb2RlbHMsIG9wdGlvbnMpIHtcbiAgICB9LFxuXG4gICAgY3JlYXRlOiBmdW5jdGlvbiAoYXR0ciwgb3B0aW9ucykge1xuICAgICAgICB2YXIgbSA9IG5ldyB0aGlzLm1vZGVsKGF0dHIsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnNldChtKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAobW9kZWxzLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMuX21vZGVscy5sZW5ndGggPSAwO1xuICAgICAgICB0aGlzLnNldChtb2RlbHMpO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uIChtb2RlbCkge1xuICAgICAgICBfLnJlbW92ZSh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbSA9PT0gbW9kZWw7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGRlbGV0ZSBtb2RlbC5jb2xsZWN0aW9uO1xuXG4gICAgICAgIHJldHVybiBtb2RlbDtcbiAgICB9LFxuXG4gICAgc2V0OiBmdW5jdGlvbiAobW9kZWxzKSB7XG4gICAgICAgIGlmICghbW9kZWxzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBtb2RlbHMgPSBbXS5jb25jYXQobW9kZWxzKTtcblxuICAgICAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIF8uZWFjaChtb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICBpZiAoIShtIGluc3RhbmNlb2YgdGhpcy5tb2RlbCkpIHtcbiAgICAgICAgICAgICAgICBtID0gbmV3IHRoaXMubW9kZWwobSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG0uY29sbGVjdGlvbiA9IHRoaXM7XG5cbiAgICAgICAgICAgIHRoaXMuX21vZGVscy5wdXNoKG0pO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICB0aGlzLnNvcnQuY2FsbCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gbW9kZWxzO1xuICAgIH0sXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBiLl9kYXRhW3RoaXMuaWRBdHRyaWJ1dGVdIC0gYS5fZGF0YVt0aGlzLmlkQXR0cmlidXRlXTtcbiAgICB9LFxuXG4gICAgc29ydDogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLl9tb2RlbHMgPSB0aGlzLl9tb2RlbHMuc29ydCh0aGlzLnNvcnRGbi5iaW5kKHRoaXMpKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzO1xuICAgIH0sXG5cbiAgICBnZXRCeUlkOiBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgcmV0dXJuIF8uZmluZCh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbS5nZXQodGhpcy5pZEF0dHJpYnV0ZSkgPT09IGlkO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgZWFjaDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uZWFjaCh0aGlzLl9tb2RlbHMsIGNiLCBjdHggfHwgdGhpcyk7XG4gICAgfSxcblxuICAgIGFsbDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uYWxsKHRoaXMuX21vZGVscywgY2IsIGN0eCB8fCB0aGlzKTtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBfLmludm9rZSh0aGlzLl9tb2RlbHMsICd0b0pTT04nKTtcbiAgICB9LFxuXG4gICAgZmluZDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbmQodGhpcy5fbW9kZWxzLCBmbik7XG4gICAgfSxcblxuICAgIGZpbHRlcjogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbHRlcih0aGlzLl9tb2RlbHMsIGZuKTtcbiAgICB9LFxuXG4gICAgc2l6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgbWFwOiBmdW5jdGlvbiAoZm4sIGN0eCkge1xuICAgICAgICByZXR1cm4gXy5tYXAodGhpcy5fbW9kZWxzLCBmdW5jdGlvbiAobW9kZWwpIHtcbiAgICAgICAgICAgIHJldHVybiBmbi5jYWxsKGN0eCwgbW9kZWwudG9KU09OKCkpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgcGx1Y2s6IGZ1bmN0aW9uIChmaWVsZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBtW2ZpZWxkXTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlQ29sbGVjdGlvbjsiLCIndXNlIHN0cmljdCc7XG5cblxudmFyIEJhc2VNb2RlbCA9IGZ1bmN0aW9uIChhdHRyLCBvcHRpb25zKSB7XG4gICAgYXR0ciA9IF8uZGVmYXVsdHMoe30sIGF0dHIsIF8ucmVzdWx0KHRoaXMsICdkZWZhdWx0cycpKTtcbiAgICB0aGlzLl9kYXRhID0ge307XG4gICAgdGhpcy5zZXQoYXR0ciwgb3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlTW9kZWwucHJvdG90eXBlLCB7XG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKGF0dHIsIG9wdGlvbnMpIHtcblxuICAgIH0sXG5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbCwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChrZXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWw7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBfLmV4dGVuZCh0aGlzLl9kYXRhLCBhdHRycyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGdldDogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YVtrZXldO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jb2xsZWN0aW9uLnJlbW92ZSh0aGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICB0b0pTT046IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGE7XG4gICAgfSxcblxuICAgIHBpY2s6IGZ1bmN0aW9uIChrZXlzKSB7XG4gICAgICAgIHJldHVybiBfLnBpY2sodGhpcy5fZGF0YSwga2V5cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlTW9kZWw7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZW52ID0ge1xuICAgIGFjY291bnQ6ICcnLFxuICAgIHByb2plY3Q6ICcnLFxuICAgIGdyb3VwOiAnJyxcbiAgICBncm91cElkOiAnJyxcbiAgICB0b2tlbjogJycsXG4gICAgc2VydmVyOiB7XG4gICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgcHJvdG9jb2w6ICdodHRwcydcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBzZXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGVudiA9IF8ubWVyZ2UoZW52LCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBlbnY7XG4gICAgfVxufTsiLCIoZnVuY3Rpb24gKCkge1xuICAgICd1c2Ugc3RyaWN0JztcbiAgICB2YXIgQXBwID0gcmVxdWlyZSgnLi9hc3NpZ25tZW50LmpzJyk7XG5cbiAgICB3aW5kb3cuZm9yaW8gPSB3aW5kb3cuZm9yaW8gfHwge307XG4gICAgd2luZG93LmZvcmlvLk11bHRpcGxheWVyQXNzaWdubWVudENvbXBvbmVudCA9IEFwcDtcbn0pKCk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBzZXJ2aWNlTG9jYXRvciA9IHJlcXVpcmUoJy4vc2VydmljZS1sb2NhdG9yJyk7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG4vLyB2YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBpc0R5bmFtaWNBc3NpZ25tZW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldCgnd29ybGRzJykgPT09ICdkeW5hbWljJztcbiAgICB9LFxuXG4gICAgaGFzUm9sZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJvbGVzID0gdGhpcy5nZXQoJ3JvbGVzJyk7XG4gICAgICAgIHJldHVybiByb2xlcyAmJiAhIXJvbGVzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGFwaSA9IHNlcnZpY2VMb2NhdG9yLndvcmxkQXBpKCk7XG5cbiAgICAgICAgcmV0dXJuIGFwaS5nZXRQcm9qZWN0U2V0dGluZ3MoKS50aGVuKGZ1bmN0aW9uIChzZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5zZXQoc2V0dGluZ3MpO1xuICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cbn0pOyIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVudiA9IHJlcXVpcmUoJy4vZGVmYXVsdHMuanMnKTtcblxudmFyIGNhY2hlID0ge307XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHdvcmxkQXBpOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghY2FjaGUud29ybGRBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLndvcmxkQXBpID0gbmV3IEYuc2VydmljZS5Xb3JsZChlbnYuZ2V0KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLndvcmxkQXBpO1xuICAgIH0sXG5cbiAgICBtZW1iZXJBcGk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFjYWNoZS5tZW1iZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLm1lbWJlckFwaSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKF8ucGljayhlbnYuZ2V0KCksIFsnZ3JvdXBJZCcsICdzZXJ2ZXInXSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLm1lbWJlckFwaTtcbiAgICB9LFxuXG4gICAgdXNlckFwaTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIWNhY2hlLnVzZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLnVzZXJBcGkgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoXy5waWNrKGVudi5nZXQoKSwgWydhY2NvdW50JywgJ3NlcnZlciddKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2FjaGUudXNlckFwaTtcbiAgICB9XG59OyIsImV4cG9ydHNbXCJlZGl0LXVzZXItcm93XCJdID0gZnVuY3Rpb24ob2JqKSB7XG5vYmogfHwgKG9iaiA9IHt9KTtcbnZhciBfX3QsIF9fcCA9ICcnLCBfX2UgPSBfLmVzY2FwZSwgX19qID0gQXJyYXkucHJvdG90eXBlLmpvaW47XG5mdW5jdGlvbiBwcmludCgpIHsgX19wICs9IF9fai5jYWxsKGFyZ3VtZW50cywgJycpIH1cbndpdGggKG9iaikge1xuX19wICs9ICc8dGQ+PGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGNsYXNzPVwic2VsZWN0XCIgZGF0YS1pZD1cIicgK1xuKChfX3QgPSAoIGlkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+PC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cIndvcmxkc1wiIGNsYXNzPVwiZm9ybS1jb250cm9sXCIgZGF0YS1maWVsZD1cIndvcmxkXCI+XFxuXFxuICAgICc7XG4gXy5lYWNoKHdvcmxkcywgZnVuY3Rpb24gKHcpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHcgPT09IHdvcmxkID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIicgK1xuKChfX3QgPSAoIG5ld1dvcmxkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiIGNsYXNzPVwibmV3LXdvcmxkLXRleHRcIj48aT4nICtcbigoX190ID0gKCBuZXdXb3JsZCApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbicgLSBOZXcgLTwvaT48L29wdGlvbj5cXG4gICAgPC9zZWxlY3Q+XFxuPC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cInJvbGVzXCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBkYXRhLWZpZWxkPVwicm9sZVwiPlxcbiAgICAnO1xuIF8uZWFjaChyb2xlcywgZnVuY3Rpb24gKHIpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHIgPT09IHJvbGUgPyAnc2VsZWN0ZWQnIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPicgK1xuKChfX3QgPSAoIHIgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC9vcHRpb24+XFxuICAgICc7XG4gfSk7IDtcbl9fcCArPSAnXFxuXFxuICAgICc7XG4gXy5lYWNoKG9wdGlvbmFsUm9sZXMsIGZ1bmN0aW9uIChyKSB7IDtcbl9fcCArPSAnXFxuICAgICAgICA8b3B0aW9uIHZhbHVlPVwiJyArXG4oKF9fdCA9ICggciApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbidcIiAnICtcbigoX190ID0gKCByID09PSByb2xlID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJyA8aT4oT3B0aW9uYWwpPC9pPjwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICA8L3NlbGVjdD5cXG48L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi10b29scyBidG4tc2F2ZSBzYXZlXCI+U2F2ZTwvYnV0dG9uPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi10b29scyBidG4tY2FuY2VsIGNhbmNlbFwiPkNhbmNlbDwvYnV0dG9uPlxcbjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTtcbmV4cG9ydHNbXCJ1c2VyLXJvd1wiXSA9IGZ1bmN0aW9uKG9iaikge1xub2JqIHx8IChvYmogPSB7fSk7XG52YXIgX190LCBfX3AgPSAnJywgX19lID0gXy5lc2NhcGU7XG53aXRoIChvYmopIHtcbl9fcCArPSAnPHRkPjxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cInNlbGVjdFwiIGRhdGEtaWQ9XCInICtcbigoX190ID0gKCBpZCkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggIWlzV29ybGRDb21wbGV0ZSA/ICc8ZW0gY2xhc3M9XCJmLWljb24gZi13YXJuaW5nXCI+PC9lbT4nIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggd29ybGQgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggcm9sZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPjxidXR0b24gY2xhc3M9XCJidG4gZWRpdCBidG4tZWRpdCBidG4tdG9vbHMgYXV0by1oaWRlXCI+RWRpdDwvYnV0dG9uPjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBkZWZhdWx0czoge1xuICAgICAgICB3b3JsZDogJycsXG4gICAgICAgIHJvbGU6ICcnLFxuICAgICAgICBhY3RpdmU6IHRydWUsXG4gICAgICAgIGlzV29ybGRDb21wbGV0ZTogdHJ1ZSxcbiAgICAgICAgZmlyc3ROYW1lOiAnJyxcbiAgICAgICAgbGFzdE5hbWU6ICcnXG4gICAgfSxcblxuICAgIG1ha2VBY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gbWVtYmVyQXBpLm1ha2VVc2VyQWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBtYWtlSW5hY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBmYWxzZSk7XG5cbiAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5tYWtlVXNlckluYWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cblxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcblxudmFyIE1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcblxuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBtb2RlbDogTW9kZWwsXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHZhciBhdyA9IGEuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBidyA9IGIuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIGlmIChhdyAhPT0gYncpIHtcbiAgICAgICAgICAgIHJldHVybiBhdyA8IGJ3ID8gLTEgOiAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGIuZ2V0KCd1c2VyTmFtZScpID4gYS5nZXQoJ3VzZXJOYW1lJykgPyAtMSA6IDE7XG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJC5hamF4U2V0dXAoe1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIGVudi5nZXQoKS50b2tlblxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgYWxsVXNlcnNBc3NpZ25lZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hbGwoZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiAhIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0VW5hc3NpZ25lZFVzZXJzQ291bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmlsdGVyKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICByZXR1cm4gIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KS5sZW5ndGg7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBncm91cElkID0gZW52LmdldCgpLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGdldEdyb3VwVXNlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbWVtYmVyQXBpID0gc2VydmljZUxvY2F0b3IubWVtYmVyQXBpKCk7XG4gICAgICAgICAgICB2YXIgdXNlckFwaSA9IHNlcnZpY2VMb2NhdG9yLnVzZXJBcGkoKTtcblxuICAgICAgICAgICAgdmFyIGxvYWRHcm91cE1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5nZXRHcm91cERldGFpbHMoKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBsb2FkVXNlcnNJbmZvID0gZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vbkZhY0FuZEFjdGl2ZSA9IGZ1bmN0aW9uICh1KSB7IHJldHVybiB1LmFjdGl2ZSAmJiB1LnJvbGUgIT09ICdmYWNpbGl0YXRvcic7IH07XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJzID0gXy5wbHVjayhfLmZpbHRlcihncm91cC5tZW1iZXJzLCBub25GYWNBbmRBY3RpdmUpLCAndXNlcklkJyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVzZXJBcGkuZ2V0KHsgaWQ6IHVzZXJzIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGxvYWRHcm91cE1lbWJlcnMoKVxuICAgICAgICAgICAgICAgIC50aGVuKGxvYWRVc2Vyc0luZm8pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgZ2V0R3JvdXBVc2VycygpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAodXNlcnMpIHtcbiAgICAgICAgICAgICAgICB1c2VycyA9IF8ubWFwKHVzZXJzLCBmdW5jdGlvbiAodSkgeyByZXR1cm4gXy5leHRlbmQodSwgeyBncm91cElkOiBncm91cElkIH0pOyB9KTtcbiAgICAgICAgICAgICAgICBfdGhpcy5zZXQodXNlcnMpO1xuICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHVzZXJzLCBfdGhpcyk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9XG5cbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBkZWZhdWx0czoge1xuICAgICAgICB1c2VyczogbnVsbCxcbiAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX19zdXBlci5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgdGhpcy5fZGF0YS51c2VycyA9IHRoaXMuX2RhdGEudXNlcnMgfHwgW107XG5cbiAgICAgICAgdGhpcy5fd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuXG4gICAgICAgIHZhciBpZCA9IHRoaXMuZ2V0KCdpZCcpO1xuICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgYWRkVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIHVzZXJzLnB1c2godXNlcik7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuc2F2ZSgpO1xuICAgIH0sXG5cbiAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlcikge1xuICAgICAgICB2YXIgaWQgPSB0aGlzLmdldCgnaWQnKTtcbiAgICAgICAgdmFyIGNoZWNrV29ybGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuZ2V0KCd1c2VycycpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSkuZGVsZXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICBfLnJlbW92ZSh0aGlzLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiB1LmdldCgnaWQnKSA9PT0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl93b3JsZEFwaVxuICAgICAgICAgICAgLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSlcbiAgICAgICAgICAgIC5yZW1vdmVVc2VyKHsgdXNlcklkOiB1c2VyLmdldCgnaWQnKSB9KVxuICAgICAgICAgICAgLnRoZW4oY2hlY2tXb3JsZCk7XG4gICAgfSxcblxuICAgIHNhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIG1hcFVzZXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIF8ubWFwKHRoaXMuZ2V0KCd1c2VycycpLCBmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgICAgIHZhciByZXMgPSB7IHVzZXJJZDogdS5nZXQoJ2lkJykgfTtcbiAgICAgICAgICAgICAgICB2YXIgcm9sZSA9IHUuZ2V0KCdyb2xlJyk7XG5cbiAgICAgICAgICAgICAgICBpZiAocm9sZSkge1xuICAgICAgICAgICAgICAgICAgICByZXMucm9sZSA9IHJvbGU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIGNyZWF0ZVdvcmxkID0gXy5wYXJ0aWFsKHRoaXMuX3dvcmxkQXBpLmNyZWF0ZSwgdGhpcy5waWNrKFsnbW9kZWwnLCAnbmFtZScsICdtaW5Vc2VycyddKSk7XG4gICAgICAgIHZhciBhZGRVc2VycyA9IF8ucGFydGlhbChfdGhpcy5fd29ybGRBcGkuYWRkVXNlcnMsIG1hcFVzZXJzKCksIHsgZmlsdGVyOiBfdGhpcy5nZXQoJ2lkJykgfSk7XG4gICAgICAgIHZhciBzYXZlZFVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIGlmICh0aGlzLmlzTmV3KCkpIHtcbiAgICAgICAgICAgIC8vIHdlIG5lZWQgdG8gY3JlYXRlIHRoZSB3b3JsZCBpbiB0aGUgQVBJIGFuZCB0aGVuIGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVXb3JsZCgpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNldCh3b3JsZCk7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLl93b3JsZEFwaS51cGRhdGVDb25maWcoeyBmaWx0ZXI6IHdvcmxkLmlkIH0pO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oYWRkVXNlcnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHVzZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHNpbmNlIHdlIHJlLXNldCB0aGUgd29ybGQsIHJlLXNldCB0aGUgdXNlcnNcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuc2V0KCd1c2VycycsIHNhdmVkVXNlcnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gdGhlIHdvcmxkIGlzIGFscmVhZHkgY3JlYXRlZCBqdXN0IGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBhZGRVc2VycygpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGlzTmV3OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5nZXQoJ2xhc3RNb2RpZmllZCcpO1xuICAgIH1cblxufSk7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgTW9kZWwgPSByZXF1aXJlKCcuL3dvcmxkLW1vZGVsJyk7XG52YXIgVXNlck1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG52YXIgZG9uZUZuID0gZnVuY3Rpb24gKGR0ZCwgYWZ0ZXIpIHtcbiAgICByZXR1cm4gXy5hZnRlcihhZnRlciwgZHRkLnJlc29sdmUpO1xufTtcblxudmFyIHdvcmxkQXBpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgbW9kZWw6IE1vZGVsLFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBfX3N1cGVyLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuICAgIH0sXG5cbiAgICBhdXRvQXNzaWduQWxsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gd29ybGRBcGkuYXV0b0Fzc2lnbihvcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzZXQodGhpcy5wYXJzZSh3b3JsZHMpKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGdldEluY29tcGxldGVXb3JsZHNDb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24gKHcpIHtcbiAgICAgICAgICAgIHJldHVybiAhdy5nZXQoJ2NvbXBsZXRlJyk7XG4gICAgICAgIH0pLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgdXBkYXRlVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHdvcmxkTmFtZSA9IHVzZXIuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgcHJldldvcmxkID0gdGhpcy5nZXRXb3JsZEJ5VXNlcih1c2VyKTtcbiAgICAgICAgdmFyIGN1cldvcmxkID0gdGhpcy5nZXRPckNyZWF0ZVdvcmxkKHdvcmxkTmFtZSk7XG4gICAgICAgIHZhciBkb25lID0gZG9uZUZuKGR0ZCwgMSk7XG5cbiAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUncyBhbnl0aGluZyB0byBkb1xuICAgICAgICBpZiAoIXByZXZXb3JsZCAmJiAhY3VyV29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiBkdGQucmVzb2x2ZSgpLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwcmV2V29ybGQpIHtcbiAgICAgICAgICAgIHByZXZXb3JsZC5yZW1vdmVVc2VyKHVzZXIpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY3VyV29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjdXJXb3JsZC5hZGRVc2VyKHVzZXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAudGhlbihkb25lKTtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJXb3JsZCkge1xuICAgICAgICAgICAgY3VyV29ybGQuYWRkVXNlcih1c2VyKVxuICAgICAgICAgICAgICAgIC50aGVuKGRvbmUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldE9yQ3JlYXRlV29ybGQ6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgaWYgKCF3b3JsZE5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB3b3JsZCA9IHRoaXMuZ2V0V29yZEJ5TmFtZSh3b3JsZE5hbWUpO1xuXG4gICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgIHdvcmxkID0gdGhpcy5jcmVhdGUoeyBuYW1lOiB3b3JsZE5hbWUgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gd29ybGQ7XG4gICAgfSxcblxuICAgIGdldFdvcmRCeU5hbWU6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmluZChmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiB3b3JsZC5nZXQoJ25hbWUnKSA9PT0gd29ybGROYW1lO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGRCeVVzZXI6IGZ1bmN0aW9uICh1c2VyKSB7XG4gICAgICAgIGlmICghdXNlci5nZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZ2V0V29ybGRCeVVzZXIgZXhwZWN0ZXMgYSBtb2RlbCAoJyArIHVzZXIgKyAnKScpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGlkID0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFdvcmxkQnlVc2VySWQoaWQpO1xuICAgIH0sXG5cbiAgICBnZXRXb3JsZEJ5VXNlcklkOiBmdW5jdGlvbiAodXNlcklkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZpbmQoZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICByZXR1cm4gXy5maW5kKHdvcmxkLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdS5nZXQoJ2lkJykgPT09IHVzZXJJZDtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGROYW1lczogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wbHVjaygnbmFtZScpO1xuICAgIH0sXG5cbiAgICBnZXROZXh0V29ybGROYW1lOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBwYWQgPSBmdW5jdGlvbiAobnVtLCBwbGFjZXMpIHtcbiAgICAgICAgICAgIHZhciB6ZXJvcyA9ICcwMDAwMDAwMDAwMDAwMDAwMDAnO1xuICAgICAgICAgICAgdmFyIGRpZ2l0cyA9IG51bS50b1N0cmluZygpLmxlbmd0aDtcbiAgICAgICAgICAgIHZhciBuZWVkZWQgPSBwbGFjZXMgLSBkaWdpdHM7XG4gICAgICAgICAgICByZXR1cm4gemVyb3Muc3Vic3RyKDAsIG5lZWRlZCkgKyBudW07XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHdvcmxkcyA9IHRoaXMuZ2V0V29ybGROYW1lcygpO1xuXG4gICAgICAgIGlmICghd29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuICdXb3JsZDAwMSc7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcHJvcGVyTmFtZXMgPSBfLmZpbHRlcih3b3JsZHMsIGZ1bmN0aW9uICh3KSB7IHJldHVybiAvV29ybGRcXGRcXGRcXGQvLnRlc3Qodyk7IH0pLnNvcnQoKTtcbiAgICAgICAgdmFyIGxhc3RXb3JsZCA9IHByb3Blck5hbWVzW3Byb3Blck5hbWVzLmxlbmd0aCAtIDFdO1xuICAgICAgICB2YXIgbnVtV29ybGQgPSArbGFzdFdvcmxkLm1hdGNoKC9Xb3JsZChcXGRcXGRcXGQpLylbMV07XG4gICAgICAgIHJldHVybiAnV29ybGQnICsgcGFkKG51bVdvcmxkICsgMSwgMyk7XG4gICAgfSxcblxuICAgIHNldFVzZXJzQ29sbGVjdGlvbjogZnVuY3Rpb24gKHVzZXJzQ29sbGVjdGlvbikge1xuICAgICAgICB0aGlzLnVzZXJzQ29sbGVjdGlvbiA9IHVzZXJzQ29sbGVjdGlvbjtcbiAgICB9LFxuXG4gICAgam9pblVzZXJzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1c2Vyc0hhc2ggPSB7fTtcbiAgICAgICAgdmFyIHVzZXJzQ29sbGVjdGlvbiA9IHRoaXMudXNlcnNDb2xsZWN0aW9uO1xuICAgICAgICB1c2Vyc0NvbGxlY3Rpb24uZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdS5zZXQoeyBpc1dvcmxkQ29tcGxldGU6IHRydWUgfSk7XG4gICAgICAgICAgICByZXR1cm4gKHVzZXJzSGFzaFt1LmdldCgnaWQnKV0gPSB1KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5lYWNoKGZ1bmN0aW9uICh3LCBpKSB7XG4gICAgICAgICAgICB2YXIgbmFtZSA9IHcuZ2V0KCduYW1lJyk7XG4gICAgICAgICAgICB2YXIgaXNDb21wbGV0ZSA9IHcuZ2V0KCdjb21wbGV0ZScpO1xuICAgICAgICAgICAgdy5zZXQoeyBpbmRleDogaSwgbmFtZTogbmFtZSB8fCAoaSArIDEpICsgJycgfSk7XG4gICAgICAgICAgICBfLmVhY2gody5nZXQoJ3VzZXJzJyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgaWYgKHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldKSB7XG4gICAgICAgICAgICAgICAgICAgIHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldLnNldCh7IHdvcmxkOiBuYW1lLCByb2xlOiB1LmdldCgncm9sZScpLCBpc1dvcmxkQ29tcGxldGU6IGlzQ29tcGxldGUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHVzZXJzQ29sbGVjdGlvbi5zb3J0KCk7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB3b3JsZEFwaS5saXN0KClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc2V0KHRoaXMucGFyc2Uod29ybGRzKSk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBwYXJzZTogZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICBpZiAod29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgd29ybGRzID0gXy5tYXAod29ybGRzLCBmdW5jdGlvbiAodykge1xuICAgICAgICAgICAgICAgIHZhciB1c2VycyA9IF8ubWFwKHcudXNlcnMsIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGluIHRoZSB3b3JsZCBhcGkgdXNlcnMgSWRzIGNvbWVzIGFzIHVzZXJJZFxuICAgICAgICAgICAgICAgICAgICAvLyBtYWtlIHN1cmUgd2UgYWRkIGl0IGFzIGlkIHNvIHdlIGNhbiB1c2UgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIHNhbWUgY29kZSB0byBhY2Nlc3MgbW9kZWxzIHRoYXQgY29tZSBmcm9tIHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyBtZW1iZXIvbG9jYWwgYXBpIGFzIHdpdGggdGhlIHdvcmxkIGFwaVxuICAgICAgICAgICAgICAgICAgICB1LmlkID0gdS51c2VySWQ7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVXNlck1vZGVsKHUpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgdy51c2VycyA9IHVzZXJzO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHc7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB3b3JsZHM7XG4gICAgfVxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuKiBVdGlsaXR5IGNsYXNzIHRvIG1ha2UgYWpheCBjYWxscyBzZXF1ZW5jaWFsXG4qL1xuZnVuY3Rpb24gQWpheFF1ZXVlICgpIHtcbiAgICB0aGlzLnF1ZXVlID0gW107XG59XG5cbiQuZXh0ZW5kKEFqYXhRdWV1ZS5wcm90b3R5cGUsIHtcbiAgICBhZGQ6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICByZXR1cm4gdGhpcy5xdWV1ZS5wdXNoKGZuKTtcbiAgICB9LFxuXG4gICAgZXhlY3V0ZTogZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgY29udGV4dCA9IGNvbnRleHQgfHwgdGhpcztcblxuICAgICAgICBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgICAgICAgaWYgKF90aGlzLnF1ZXVlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBmbiA9IF90aGlzLnF1ZXVlLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgICAgICBmbi5jYWxsKGNvbnRleHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKG5leHQpXG4gICAgICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbmV4dCgpO1xuXG4gICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQWpheFF1ZXVlOyIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiJdfQ== diff --git a/dist/epicenter.js b/dist/epicenter.js index 572cad94..dc1ae32f 100644 --- a/dist/epicenter.js +++ b/dist/epicenter.js @@ -1940,6 +1940,8 @@ function AuthManager(options) { this.options = $.extend(true, {}, defaults, options); var urlConfig = new ConfigService(this.options).get('server'); + this.isLocal = urlConfig.isLocalhost(); + if (!this.options.account) { this.options.account = urlConfig.accountPath; } @@ -2016,7 +2018,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { var projectName = (options && options.project) ? options.project : this.options.project; if (this.options.store.root === undefined && accountName && projectName) { - this.store.serviceOptions.root = '/app/' + accountName + '/' + projectName; + this.store.serviceOptions.root = this.isLocal ? '/' : '/app/' + accountName + '/' + projectName; } var decodeToken = function (token) { @@ -7449,4 +7451,4 @@ module.exports = (function () { }()); },{"./query-util":44}]},{},[6]) -//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL25vZGVfbW9kdWxlcy9pZWVlNzU0L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvaXMtYXJyYXkvaW5kZXguanMiLCJzcmMvYXBpLXZlcnNpb24uanNvbiIsInNyYy9hcHAuanMiLCJzcmMvbWFuYWdlcnMvYXV0aC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2NoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2tleS1uYW1lcy5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9hbHdheXMtbmV3LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2lkZW50aXR5LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL211bHRpcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcC5qcyIsInNyYy9tYW5hZ2Vycy9zY2VuYXJpby1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3NwZWNpYWwtb3BlcmF0aW9ucy5qcyIsInNyYy9tYW5hZ2Vycy93b3JsZC1tYW5hZ2VyLmpzIiwic3JjL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyLmpzIiwic3JjL3N0b3JlL2Nvb2tpZS1zdG9yZS5qcyIsInNyYy9zdG9yZS9zdG9yZS1mYWN0b3J5LmpzIiwic3JjL3RyYW5zcG9ydC9hamF4LWh0dHAtdHJhbnNwb3J0LmpzIiwic3JjL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5LmpzIiwic3JjL3V0aWwvaW5oZXJpdC5qcyIsInNyYy91dGlsL21ha2Utc2VxdWVuY2UuanMiLCJzcmMvdXRpbC9vYmplY3QtdXRpbC5qcyIsInNyYy91dGlsL3F1ZXJ5LXV0aWwuanMiLCJzcmMvdXRpbC9ydW4tdXRpbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN4Z0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxV0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMVRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0UUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25LQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzdUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLyohXG4gKiBUaGUgYnVmZmVyIG1vZHVsZSBmcm9tIG5vZGUuanMsIGZvciB0aGUgYnJvd3Nlci5cbiAqXG4gKiBAYXV0aG9yICAgRmVyb3NzIEFib3VraGFkaWplaCA8ZmVyb3NzQGZlcm9zcy5vcmc+IDxodHRwOi8vZmVyb3NzLm9yZz5cbiAqIEBsaWNlbnNlICBNSVRcbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tcHJvdG8gKi9cblxudmFyIGJhc2U2NCA9IHJlcXVpcmUoJ2Jhc2U2NC1qcycpXG52YXIgaWVlZTc1NCA9IHJlcXVpcmUoJ2llZWU3NTQnKVxudmFyIGlzQXJyYXkgPSByZXF1aXJlKCdpcy1hcnJheScpXG5cbmV4cG9ydHMuQnVmZmVyID0gQnVmZmVyXG5leHBvcnRzLlNsb3dCdWZmZXIgPSBTbG93QnVmZmVyXG5leHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTID0gNTBcbkJ1ZmZlci5wb29sU2l6ZSA9IDgxOTIgLy8gbm90IHVzZWQgYnkgdGhpcyBpbXBsZW1lbnRhdGlvblxuXG52YXIgcm9vdFBhcmVudCA9IHt9XG5cbi8qKlxuICogSWYgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYDpcbiAqICAgPT09IHRydWUgICAgVXNlIFVpbnQ4QXJyYXkgaW1wbGVtZW50YXRpb24gKGZhc3Rlc3QpXG4gKiAgID09PSBmYWxzZSAgIFVzZSBPYmplY3QgaW1wbGVtZW50YXRpb24gKG1vc3QgY29tcGF0aWJsZSwgZXZlbiBJRTYpXG4gKlxuICogQnJvd3NlcnMgdGhhdCBzdXBwb3J0IHR5cGVkIGFycmF5cyBhcmUgSUUgMTArLCBGaXJlZm94IDQrLCBDaHJvbWUgNyssIFNhZmFyaSA1LjErLFxuICogT3BlcmEgMTEuNissIGlPUyA0LjIrLlxuICpcbiAqIER1ZSB0byB2YXJpb3VzIGJyb3dzZXIgYnVncywgc29tZXRpbWVzIHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24gd2lsbCBiZSB1c2VkIGV2ZW5cbiAqIHdoZW4gdGhlIGJyb3dzZXIgc3VwcG9ydHMgdHlwZWQgYXJyYXlzLlxuICpcbiAqIE5vdGU6XG4gKlxuICogICAtIEZpcmVmb3ggNC0yOSBsYWNrcyBzdXBwb3J0IGZvciBhZGRpbmcgbmV3IHByb3BlcnRpZXMgdG8gYFVpbnQ4QXJyYXlgIGluc3RhbmNlcyxcbiAqICAgICBTZWU6IGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTY5NTQzOC5cbiAqXG4gKiAgIC0gU2FmYXJpIDUtNyBsYWNrcyBzdXBwb3J0IGZvciBjaGFuZ2luZyB0aGUgYE9iamVjdC5wcm90b3R5cGUuY29uc3RydWN0b3JgIHByb3BlcnR5XG4gKiAgICAgb24gb2JqZWN0cy5cbiAqXG4gKiAgIC0gQ2hyb21lIDktMTAgaXMgbWlzc2luZyB0aGUgYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbi5cbiAqXG4gKiAgIC0gSUUxMCBoYXMgYSBicm9rZW4gYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGFycmF5cyBvZlxuICogICAgIGluY29ycmVjdCBsZW5ndGggaW4gc29tZSBzaXR1YXRpb25zLlxuXG4gKiBXZSBkZXRlY3QgdGhlc2UgYnVnZ3kgYnJvd3NlcnMgYW5kIHNldCBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgIHRvIGBmYWxzZWAgc28gdGhleVxuICogZ2V0IHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24sIHdoaWNoIGlzIHNsb3dlciBidXQgYmVoYXZlcyBjb3JyZWN0bHkuXG4gKi9cbkJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUID0gZ2xvYmFsLlRZUEVEX0FSUkFZX1NVUFBPUlQgIT09IHVuZGVmaW5lZFxuICA/IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gIDogdHlwZWRBcnJheVN1cHBvcnQoKVxuXG5mdW5jdGlvbiB0eXBlZEFycmF5U3VwcG9ydCAoKSB7XG4gIGZ1bmN0aW9uIEJhciAoKSB7fVxuICB0cnkge1xuICAgIHZhciBhcnIgPSBuZXcgVWludDhBcnJheSgxKVxuICAgIGFyci5mb28gPSBmdW5jdGlvbiAoKSB7IHJldHVybiA0MiB9XG4gICAgYXJyLmNvbnN0cnVjdG9yID0gQmFyXG4gICAgcmV0dXJuIGFyci5mb28oKSA9PT0gNDIgJiYgLy8gdHlwZWQgYXJyYXkgaW5zdGFuY2VzIGNhbiBiZSBhdWdtZW50ZWRcbiAgICAgICAgYXJyLmNvbnN0cnVjdG9yID09PSBCYXIgJiYgLy8gY29uc3RydWN0b3IgY2FuIGJlIHNldFxuICAgICAgICB0eXBlb2YgYXJyLnN1YmFycmF5ID09PSAnZnVuY3Rpb24nICYmIC8vIGNocm9tZSA5LTEwIGxhY2sgYHN1YmFycmF5YFxuICAgICAgICBhcnIuc3ViYXJyYXkoMSwgMSkuYnl0ZUxlbmd0aCA9PT0gMCAvLyBpZTEwIGhhcyBicm9rZW4gYHN1YmFycmF5YFxuICB9IGNhdGNoIChlKSB7XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuZnVuY3Rpb24ga01heExlbmd0aCAoKSB7XG4gIHJldHVybiBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVFxuICAgID8gMHg3ZmZmZmZmZlxuICAgIDogMHgzZmZmZmZmZlxufVxuXG4vKipcbiAqIENsYXNzOiBCdWZmZXJcbiAqID09PT09PT09PT09PT1cbiAqXG4gKiBUaGUgQnVmZmVyIGNvbnN0cnVjdG9yIHJldHVybnMgaW5zdGFuY2VzIG9mIGBVaW50OEFycmF5YCB0aGF0IGFyZSBhdWdtZW50ZWRcbiAqIHdpdGggZnVuY3Rpb24gcHJvcGVydGllcyBmb3IgYWxsIHRoZSBub2RlIGBCdWZmZXJgIEFQSSBmdW5jdGlvbnMuIFdlIHVzZVxuICogYFVpbnQ4QXJyYXlgIHNvIHRoYXQgc3F1YXJlIGJyYWNrZXQgbm90YXRpb24gd29ya3MgYXMgZXhwZWN0ZWQgLS0gaXQgcmV0dXJuc1xuICogYSBzaW5nbGUgb2N0ZXQuXG4gKlxuICogQnkgYXVnbWVudGluZyB0aGUgaW5zdGFuY2VzLCB3ZSBjYW4gYXZvaWQgbW9kaWZ5aW5nIHRoZSBgVWludDhBcnJheWBcbiAqIHByb3RvdHlwZS5cbiAqL1xuZnVuY3Rpb24gQnVmZmVyIChhcmcpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIEJ1ZmZlcikpIHtcbiAgICAvLyBBdm9pZCBnb2luZyB0aHJvdWdoIGFuIEFyZ3VtZW50c0FkYXB0b3JUcmFtcG9saW5lIGluIHRoZSBjb21tb24gY2FzZS5cbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIHJldHVybiBuZXcgQnVmZmVyKGFyZywgYXJndW1lbnRzWzFdKVxuICAgIHJldHVybiBuZXcgQnVmZmVyKGFyZylcbiAgfVxuXG4gIHRoaXMubGVuZ3RoID0gMFxuICB0aGlzLnBhcmVudCA9IHVuZGVmaW5lZFxuXG4gIC8vIENvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ251bWJlcicpIHtcbiAgICByZXR1cm4gZnJvbU51bWJlcih0aGlzLCBhcmcpXG4gIH1cblxuICAvLyBTbGlnaHRseSBsZXNzIGNvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gZnJvbVN0cmluZyh0aGlzLCBhcmcsIGFyZ3VtZW50cy5sZW5ndGggPiAxID8gYXJndW1lbnRzWzFdIDogJ3V0ZjgnKVxuICB9XG5cbiAgLy8gVW51c3VhbC5cbiAgcmV0dXJuIGZyb21PYmplY3QodGhpcywgYXJnKVxufVxuXG5mdW5jdGlvbiBmcm9tTnVtYmVyICh0aGF0LCBsZW5ndGgpIHtcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aCA8IDAgPyAwIDogY2hlY2tlZChsZW5ndGgpIHwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHRoYXRbaV0gPSAwXG4gICAgfVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21TdHJpbmcgKHRoYXQsIHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBlbmNvZGluZyAhPT0gJ3N0cmluZycgfHwgZW5jb2RpbmcgPT09ICcnKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIC8vIEFzc3VtcHRpb246IGJ5dGVMZW5ndGgoKSByZXR1cm4gdmFsdWUgaXMgYWx3YXlzIDwga01heExlbmd0aC5cbiAgdmFyIGxlbmd0aCA9IGJ5dGVMZW5ndGgoc3RyaW5nLCBlbmNvZGluZykgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG5cbiAgdGhhdC53cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihvYmplY3QpKSByZXR1cm4gZnJvbUJ1ZmZlcih0aGF0LCBvYmplY3QpXG5cbiAgaWYgKGlzQXJyYXkob2JqZWN0KSkgcmV0dXJuIGZyb21BcnJheSh0aGF0LCBvYmplY3QpXG5cbiAgaWYgKG9iamVjdCA9PSBudWxsKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignbXVzdCBzdGFydCB3aXRoIG51bWJlciwgYnVmZmVyLCBhcnJheSBvciBzdHJpbmcnKVxuICB9XG5cbiAgaWYgKHR5cGVvZiBBcnJheUJ1ZmZlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAob2JqZWN0LmJ1ZmZlciBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgICByZXR1cm4gZnJvbVR5cGVkQXJyYXkodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgICBpZiAob2JqZWN0IGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICAgIHJldHVybiBmcm9tQXJyYXlCdWZmZXIodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgfVxuXG4gIGlmIChvYmplY3QubGVuZ3RoKSByZXR1cm4gZnJvbUFycmF5TGlrZSh0aGF0LCBvYmplY3QpXG5cbiAgcmV0dXJuIGZyb21Kc29uT2JqZWN0KHRoYXQsIG9iamVjdClcbn1cblxuZnVuY3Rpb24gZnJvbUJ1ZmZlciAodGhhdCwgYnVmZmVyKSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGJ1ZmZlci5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICBidWZmZXIuY29weSh0aGF0LCAwLCAwLCBsZW5ndGgpXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheSAodGhhdCwgYXJyYXkpIHtcbiAgdmFyIGxlbmd0aCA9IGNoZWNrZWQoYXJyYXkubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbi8vIER1cGxpY2F0ZSBvZiBmcm9tQXJyYXkoKSB0byBrZWVwIGZyb21BcnJheSgpIG1vbm9tb3JwaGljLlxuZnVuY3Rpb24gZnJvbVR5cGVkQXJyYXkgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIC8vIFRydW5jYXRpbmcgdGhlIGVsZW1lbnRzIGlzIHByb2JhYmx5IG5vdCB3aGF0IHBlb3BsZSBleHBlY3QgZnJvbSB0eXBlZFxuICAvLyBhcnJheXMgd2l0aCBCWVRFU19QRVJfRUxFTUVOVCA+IDEgYnV0IGl0J3MgY29tcGF0aWJsZSB3aXRoIHRoZSBiZWhhdmlvclxuICAvLyBvZiB0aGUgb2xkIEJ1ZmZlciBjb25zdHJ1Y3Rvci5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUJ1ZmZlciAodGhhdCwgYXJyYXkpIHtcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgYXJyYXkuYnl0ZUxlbmd0aFxuICAgIHRoYXQgPSBCdWZmZXIuX2F1Z21lbnQobmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0ID0gZnJvbVR5cGVkQXJyYXkodGhhdCwgbmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUxpa2UgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vLyBEZXNlcmlhbGl6ZSB7IHR5cGU6ICdCdWZmZXInLCBkYXRhOiBbMSwyLDMsLi4uXSB9IGludG8gYSBCdWZmZXIgb2JqZWN0LlxuLy8gUmV0dXJucyBhIHplcm8tbGVuZ3RoIGJ1ZmZlciBmb3IgaW5wdXRzIHRoYXQgZG9uJ3QgY29uZm9ybSB0byB0aGUgc3BlYy5cbmZ1bmN0aW9uIGZyb21Kc29uT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgdmFyIGFycmF5XG4gIHZhciBsZW5ndGggPSAwXG5cbiAgaWYgKG9iamVjdC50eXBlID09PSAnQnVmZmVyJyAmJiBpc0FycmF5KG9iamVjdC5kYXRhKSkge1xuICAgIGFycmF5ID0gb2JqZWN0LmRhdGFcbiAgICBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIH1cbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gIEJ1ZmZlci5wcm90b3R5cGUuX19wcm90b19fID0gVWludDhBcnJheS5wcm90b3R5cGVcbiAgQnVmZmVyLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXlcbn1cblxuZnVuY3Rpb24gYWxsb2NhdGUgKHRoYXQsIGxlbmd0aCkge1xuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAvLyBSZXR1cm4gYW4gYXVnbWVudGVkIGBVaW50OEFycmF5YCBpbnN0YW5jZSwgZm9yIGJlc3QgcGVyZm9ybWFuY2VcbiAgICB0aGF0ID0gQnVmZmVyLl9hdWdtZW50KG5ldyBVaW50OEFycmF5KGxlbmd0aCkpXG4gICAgdGhhdC5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgLy8gRmFsbGJhY2s6IFJldHVybiBhbiBvYmplY3QgaW5zdGFuY2Ugb2YgdGhlIEJ1ZmZlciBjbGFzc1xuICAgIHRoYXQubGVuZ3RoID0gbGVuZ3RoXG4gICAgdGhhdC5faXNCdWZmZXIgPSB0cnVlXG4gIH1cblxuICB2YXIgZnJvbVBvb2wgPSBsZW5ndGggIT09IDAgJiYgbGVuZ3RoIDw9IEJ1ZmZlci5wb29sU2l6ZSA+Pj4gMVxuICBpZiAoZnJvbVBvb2wpIHRoYXQucGFyZW50ID0gcm9vdFBhcmVudFxuXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGNoZWNrZWQgKGxlbmd0aCkge1xuICAvLyBOb3RlOiBjYW5ub3QgdXNlIGBsZW5ndGggPCBrTWF4TGVuZ3RoYCBoZXJlIGJlY2F1c2UgdGhhdCBmYWlscyB3aGVuXG4gIC8vIGxlbmd0aCBpcyBOYU4gKHdoaWNoIGlzIG90aGVyd2lzZSBjb2VyY2VkIHRvIHplcm8uKVxuICBpZiAobGVuZ3RoID49IGtNYXhMZW5ndGgoKSkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIGFsbG9jYXRlIEJ1ZmZlciBsYXJnZXIgdGhhbiBtYXhpbXVtICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICdzaXplOiAweCcgKyBrTWF4TGVuZ3RoKCkudG9TdHJpbmcoMTYpICsgJyBieXRlcycpXG4gIH1cbiAgcmV0dXJuIGxlbmd0aCB8IDBcbn1cblxuZnVuY3Rpb24gU2xvd0J1ZmZlciAoc3ViamVjdCwgZW5jb2RpbmcpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFNsb3dCdWZmZXIpKSByZXR1cm4gbmV3IFNsb3dCdWZmZXIoc3ViamVjdCwgZW5jb2RpbmcpXG5cbiAgdmFyIGJ1ZiA9IG5ldyBCdWZmZXIoc3ViamVjdCwgZW5jb2RpbmcpXG4gIGRlbGV0ZSBidWYucGFyZW50XG4gIHJldHVybiBidWZcbn1cblxuQnVmZmVyLmlzQnVmZmVyID0gZnVuY3Rpb24gaXNCdWZmZXIgKGIpIHtcbiAgcmV0dXJuICEhKGIgIT0gbnVsbCAmJiBiLl9pc0J1ZmZlcilcbn1cblxuQnVmZmVyLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChhLCBiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGEpIHx8ICFCdWZmZXIuaXNCdWZmZXIoYikpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudHMgbXVzdCBiZSBCdWZmZXJzJylcbiAgfVxuXG4gIGlmIChhID09PSBiKSByZXR1cm4gMFxuXG4gIHZhciB4ID0gYS5sZW5ndGhcbiAgdmFyIHkgPSBiLmxlbmd0aFxuXG4gIHZhciBpID0gMFxuICB2YXIgbGVuID0gTWF0aC5taW4oeCwgeSlcbiAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICBpZiAoYVtpXSAhPT0gYltpXSkgYnJlYWtcblxuICAgICsraVxuICB9XG5cbiAgaWYgKGkgIT09IGxlbikge1xuICAgIHggPSBhW2ldXG4gICAgeSA9IGJbaV1cbiAgfVxuXG4gIGlmICh4IDwgeSkgcmV0dXJuIC0xXG4gIGlmICh5IDwgeCkgcmV0dXJuIDFcbiAgcmV0dXJuIDBcbn1cblxuQnVmZmVyLmlzRW5jb2RpbmcgPSBmdW5jdGlvbiBpc0VuY29kaW5nIChlbmNvZGluZykge1xuICBzd2l0Y2ggKFN0cmluZyhlbmNvZGluZykudG9Mb3dlckNhc2UoKSkge1xuICAgIGNhc2UgJ2hleCc6XG4gICAgY2FzZSAndXRmOCc6XG4gICAgY2FzZSAndXRmLTgnOlxuICAgIGNhc2UgJ2FzY2lpJzpcbiAgICBjYXNlICdiaW5hcnknOlxuICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgY2FzZSAncmF3JzpcbiAgICBjYXNlICd1Y3MyJzpcbiAgICBjYXNlICd1Y3MtMic6XG4gICAgY2FzZSAndXRmMTZsZSc6XG4gICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgcmV0dXJuIHRydWVcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuQnVmZmVyLmNvbmNhdCA9IGZ1bmN0aW9uIGNvbmNhdCAobGlzdCwgbGVuZ3RoKSB7XG4gIGlmICghaXNBcnJheShsaXN0KSkgdGhyb3cgbmV3IFR5cGVFcnJvcignbGlzdCBhcmd1bWVudCBtdXN0IGJlIGFuIEFycmF5IG9mIEJ1ZmZlcnMuJylcblxuICBpZiAobGlzdC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcigwKVxuICB9XG5cbiAgdmFyIGlcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbGVuZ3RoID0gMFxuICAgIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBsZW5ndGggKz0gbGlzdFtpXS5sZW5ndGhcbiAgICB9XG4gIH1cblxuICB2YXIgYnVmID0gbmV3IEJ1ZmZlcihsZW5ndGgpXG4gIHZhciBwb3MgPSAwXG4gIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGl0ZW0gPSBsaXN0W2ldXG4gICAgaXRlbS5jb3B5KGJ1ZiwgcG9zKVxuICAgIHBvcyArPSBpdGVtLmxlbmd0aFxuICB9XG4gIHJldHVybiBidWZcbn1cblxuZnVuY3Rpb24gYnl0ZUxlbmd0aCAoc3RyaW5nLCBlbmNvZGluZykge1xuICBpZiAodHlwZW9mIHN0cmluZyAhPT0gJ3N0cmluZycpIHN0cmluZyA9ICcnICsgc3RyaW5nXG5cbiAgdmFyIGxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKGxlbiA9PT0gMCkgcmV0dXJuIDBcblxuICAvLyBVc2UgYSBmb3IgbG9vcCB0byBhdm9pZCByZWN1cnNpb25cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAvLyBEZXByZWNhdGVkXG4gICAgICBjYXNlICdyYXcnOlxuICAgICAgY2FzZSAncmF3cyc6XG4gICAgICAgIHJldHVybiBsZW5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGhcbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiBsZW4gKiAyXG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gbGVuID4+PiAxXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICByZXR1cm4gYmFzZTY0VG9CeXRlcyhzdHJpbmcpLmxlbmd0aFxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSByZXR1cm4gdXRmOFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGggLy8gYXNzdW1lIHV0ZjhcbiAgICAgICAgZW5jb2RpbmcgPSAoJycgKyBlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cbkJ1ZmZlci5ieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aFxuXG4vLyBwcmUtc2V0IGZvciB2YWx1ZXMgdGhhdCBtYXkgZXhpc3QgaW4gdGhlIGZ1dHVyZVxuQnVmZmVyLnByb3RvdHlwZS5sZW5ndGggPSB1bmRlZmluZWRcbkJ1ZmZlci5wcm90b3R5cGUucGFyZW50ID0gdW5kZWZpbmVkXG5cbmZ1bmN0aW9uIHNsb3dUb1N0cmluZyAoZW5jb2RpbmcsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcblxuICBzdGFydCA9IHN0YXJ0IHwgMFxuICBlbmQgPSBlbmQgPT09IHVuZGVmaW5lZCB8fCBlbmQgPT09IEluZmluaXR5ID8gdGhpcy5sZW5ndGggOiBlbmQgfCAwXG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcbiAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKGVuZCA8PSBzdGFydCkgcmV0dXJuICcnXG5cbiAgd2hpbGUgKHRydWUpIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1dGYxNmxlU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKGVuY29kaW5nICsgJycpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9TdHJpbmcgPSBmdW5jdGlvbiB0b1N0cmluZyAoKSB7XG4gIHZhciBsZW5ndGggPSB0aGlzLmxlbmd0aCB8IDBcbiAgaWYgKGxlbmd0aCA9PT0gMCkgcmV0dXJuICcnXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSByZXR1cm4gdXRmOFNsaWNlKHRoaXMsIDAsIGxlbmd0aClcbiAgcmV0dXJuIHNsb3dUb1N0cmluZy5hcHBseSh0aGlzLCBhcmd1bWVudHMpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24gZXF1YWxzIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiB0cnVlXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKSA9PT0gMFxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluc3BlY3QgPSBmdW5jdGlvbiBpbnNwZWN0ICgpIHtcbiAgdmFyIHN0ciA9ICcnXG4gIHZhciBtYXggPSBleHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTXG4gIGlmICh0aGlzLmxlbmd0aCA+IDApIHtcbiAgICBzdHIgPSB0aGlzLnRvU3RyaW5nKCdoZXgnLCAwLCBtYXgpLm1hdGNoKC8uezJ9L2cpLmpvaW4oJyAnKVxuICAgIGlmICh0aGlzLmxlbmd0aCA+IG1heCkgc3RyICs9ICcgLi4uICdcbiAgfVxuICByZXR1cm4gJzxCdWZmZXIgJyArIHN0ciArICc+J1xufVxuXG5CdWZmZXIucHJvdG90eXBlLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiAwXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluZGV4T2YgPSBmdW5jdGlvbiBpbmRleE9mICh2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgaWYgKGJ5dGVPZmZzZXQgPiAweDdmZmZmZmZmKSBieXRlT2Zmc2V0ID0gMHg3ZmZmZmZmZlxuICBlbHNlIGlmIChieXRlT2Zmc2V0IDwgLTB4ODAwMDAwMDApIGJ5dGVPZmZzZXQgPSAtMHg4MDAwMDAwMFxuICBieXRlT2Zmc2V0ID4+PSAwXG5cbiAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gLTFcbiAgaWYgKGJ5dGVPZmZzZXQgPj0gdGhpcy5sZW5ndGgpIHJldHVybiAtMVxuXG4gIC8vIE5lZ2F0aXZlIG9mZnNldHMgc3RhcnQgZnJvbSB0aGUgZW5kIG9mIHRoZSBidWZmZXJcbiAgaWYgKGJ5dGVPZmZzZXQgPCAwKSBieXRlT2Zmc2V0ID0gTWF0aC5tYXgodGhpcy5sZW5ndGggKyBieXRlT2Zmc2V0LCAwKVxuXG4gIGlmICh0eXBlb2YgdmFsID09PSAnc3RyaW5nJykge1xuICAgIGlmICh2YWwubGVuZ3RoID09PSAwKSByZXR1cm4gLTEgLy8gc3BlY2lhbCBjYXNlOiBsb29raW5nIGZvciBlbXB0eSBzdHJpbmcgYWx3YXlzIGZhaWxzXG4gICAgcmV0dXJuIFN0cmluZy5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAoQnVmZmVyLmlzQnVmZmVyKHZhbCkpIHtcbiAgICByZXR1cm4gYXJyYXlJbmRleE9mKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ251bWJlcicpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQgJiYgVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgcmV0dXJuIFVpbnQ4QXJyYXkucHJvdG90eXBlLmluZGV4T2YuY2FsbCh0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gICAgfVxuICAgIHJldHVybiBhcnJheUluZGV4T2YodGhpcywgWyB2YWwgXSwgYnl0ZU9mZnNldClcbiAgfVxuXG4gIGZ1bmN0aW9uIGFycmF5SW5kZXhPZiAoYXJyLCB2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgICB2YXIgZm91bmRJbmRleCA9IC0xXG4gICAgZm9yICh2YXIgaSA9IDA7IGJ5dGVPZmZzZXQgKyBpIDwgYXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoYXJyW2J5dGVPZmZzZXQgKyBpXSA9PT0gdmFsW2ZvdW5kSW5kZXggPT09IC0xID8gMCA6IGkgLSBmb3VuZEluZGV4XSkge1xuICAgICAgICBpZiAoZm91bmRJbmRleCA9PT0gLTEpIGZvdW5kSW5kZXggPSBpXG4gICAgICAgIGlmIChpIC0gZm91bmRJbmRleCArIDEgPT09IHZhbC5sZW5ndGgpIHJldHVybiBieXRlT2Zmc2V0ICsgZm91bmRJbmRleFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZm91bmRJbmRleCA9IC0xXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAtMVxuICB9XG5cbiAgdGhyb3cgbmV3IFR5cGVFcnJvcigndmFsIG11c3QgYmUgc3RyaW5nLCBudW1iZXIgb3IgQnVmZmVyJylcbn1cblxuLy8gYGdldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5nZXQgPSBmdW5jdGlvbiBnZXQgKG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLmdldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMucmVhZFVJbnQ4KG9mZnNldClcbn1cblxuLy8gYHNldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5zZXQgPSBmdW5jdGlvbiBzZXQgKHYsIG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLnNldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMud3JpdGVVSW50OCh2LCBvZmZzZXQpXG59XG5cbmZ1bmN0aW9uIGhleFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgb2Zmc2V0ID0gTnVtYmVyKG9mZnNldCkgfHwgMFxuICB2YXIgcmVtYWluaW5nID0gYnVmLmxlbmd0aCAtIG9mZnNldFxuICBpZiAoIWxlbmd0aCkge1xuICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICB9IGVsc2Uge1xuICAgIGxlbmd0aCA9IE51bWJlcihsZW5ndGgpXG4gICAgaWYgKGxlbmd0aCA+IHJlbWFpbmluZykge1xuICAgICAgbGVuZ3RoID0gcmVtYWluaW5nXG4gICAgfVxuICB9XG5cbiAgLy8gbXVzdCBiZSBhbiBldmVuIG51bWJlciBvZiBkaWdpdHNcbiAgdmFyIHN0ckxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKHN0ckxlbiAlIDIgIT09IDApIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcblxuICBpZiAobGVuZ3RoID4gc3RyTGVuIC8gMikge1xuICAgIGxlbmd0aCA9IHN0ckxlbiAvIDJcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHBhcnNlZCA9IHBhcnNlSW50KHN0cmluZy5zdWJzdHIoaSAqIDIsIDIpLCAxNilcbiAgICBpZiAoaXNOYU4ocGFyc2VkKSkgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGhleCBzdHJpbmcnKVxuICAgIGJ1ZltvZmZzZXQgKyBpXSA9IHBhcnNlZFxuICB9XG4gIHJldHVybiBpXG59XG5cbmZ1bmN0aW9uIHV0ZjhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKHV0ZjhUb0J5dGVzKHN0cmluZywgYnVmLmxlbmd0aCAtIG9mZnNldCksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGFzY2lpV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcihhc2NpaVRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYmluYXJ5V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYXNjaWlXcml0ZShidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGJhc2U2NFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIoYmFzZTY0VG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiB1Y3MyV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcih1dGYxNmxlVG9CeXRlcyhzdHJpbmcsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlID0gZnVuY3Rpb24gd3JpdGUgKHN0cmluZywgb2Zmc2V0LCBsZW5ndGgsIGVuY29kaW5nKSB7XG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcpXG4gIGlmIChvZmZzZXQgPT09IHVuZGVmaW5lZCkge1xuICAgIGVuY29kaW5nID0gJ3V0ZjgnXG4gICAgbGVuZ3RoID0gdGhpcy5sZW5ndGhcbiAgICBvZmZzZXQgPSAwXG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICB9IGVsc2UgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkICYmIHR5cGVvZiBvZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgZW5jb2RpbmcgPSBvZmZzZXRcbiAgICBsZW5ndGggPSB0aGlzLmxlbmd0aFxuICAgIG9mZnNldCA9IDBcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZywgb2Zmc2V0WywgbGVuZ3RoXVssIGVuY29kaW5nXSlcbiAgfSBlbHNlIGlmIChpc0Zpbml0ZShvZmZzZXQpKSB7XG4gICAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICAgIGlmIChpc0Zpbml0ZShsZW5ndGgpKSB7XG4gICAgICBsZW5ndGggPSBsZW5ndGggfCAwXG4gICAgICBpZiAoZW5jb2RpbmcgPT09IHVuZGVmaW5lZCkgZW5jb2RpbmcgPSAndXRmOCdcbiAgICB9IGVsc2Uge1xuICAgICAgZW5jb2RpbmcgPSBsZW5ndGhcbiAgICAgIGxlbmd0aCA9IHVuZGVmaW5lZFxuICAgIH1cbiAgLy8gbGVnYWN5IHdyaXRlKHN0cmluZywgZW5jb2RpbmcsIG9mZnNldCwgbGVuZ3RoKSAtIHJlbW92ZSBpbiB2MC4xM1xuICB9IGVsc2Uge1xuICAgIHZhciBzd2FwID0gZW5jb2RpbmdcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIG9mZnNldCA9IGxlbmd0aCB8IDBcbiAgICBsZW5ndGggPSBzd2FwXG4gIH1cblxuICB2YXIgcmVtYWluaW5nID0gdGhpcy5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkIHx8IGxlbmd0aCA+IHJlbWFpbmluZykgbGVuZ3RoID0gcmVtYWluaW5nXG5cbiAgaWYgKChzdHJpbmcubGVuZ3RoID4gMCAmJiAobGVuZ3RoIDwgMCB8fCBvZmZzZXQgPCAwKSkgfHwgb2Zmc2V0ID4gdGhpcy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignYXR0ZW1wdCB0byB3cml0ZSBvdXRzaWRlIGJ1ZmZlciBib3VuZHMnKVxuICB9XG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcblxuICB2YXIgbG93ZXJlZENhc2UgPSBmYWxzZVxuICBmb3IgKDs7KSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGhleFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgICAgcmV0dXJuIGFzY2lpV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgICAgcmV0dXJuIGJpbmFyeVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIC8vIFdhcm5pbmc6IG1heExlbmd0aCBub3QgdGFrZW4gaW50byBhY2NvdW50IGluIGJhc2U2NFdyaXRlXG4gICAgICAgIHJldHVybiBiYXNlNjRXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gdWNzMldyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgICAgICBlbmNvZGluZyA9ICgnJyArIGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvSlNPTiA9IGZ1bmN0aW9uIHRvSlNPTiAoKSB7XG4gIHJldHVybiB7XG4gICAgdHlwZTogJ0J1ZmZlcicsXG4gICAgZGF0YTogQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodGhpcy5fYXJyIHx8IHRoaXMsIDApXG4gIH1cbn1cblxuZnVuY3Rpb24gYmFzZTY0U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICBpZiAoc3RhcnQgPT09IDAgJiYgZW5kID09PSBidWYubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGJhc2U2NC5mcm9tQnl0ZUFycmF5KGJ1ZilcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmLnNsaWNlKHN0YXJ0LCBlbmQpKVxuICB9XG59XG5cbmZ1bmN0aW9uIHV0ZjhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcbiAgdmFyIHJlcyA9IFtdXG5cbiAgdmFyIGkgPSBzdGFydFxuICB3aGlsZSAoaSA8IGVuZCkge1xuICAgIHZhciBmaXJzdEJ5dGUgPSBidWZbaV1cbiAgICB2YXIgY29kZVBvaW50ID0gbnVsbFxuICAgIHZhciBieXRlc1BlclNlcXVlbmNlID0gKGZpcnN0Qnl0ZSA+IDB4RUYpID8gNFxuICAgICAgOiAoZmlyc3RCeXRlID4gMHhERikgPyAzXG4gICAgICA6IChmaXJzdEJ5dGUgPiAweEJGKSA/IDJcbiAgICAgIDogMVxuXG4gICAgaWYgKGkgKyBieXRlc1BlclNlcXVlbmNlIDw9IGVuZCkge1xuICAgICAgdmFyIHNlY29uZEJ5dGUsIHRoaXJkQnl0ZSwgZm91cnRoQnl0ZSwgdGVtcENvZGVQb2ludFxuXG4gICAgICBzd2l0Y2ggKGJ5dGVzUGVyU2VxdWVuY2UpIHtcbiAgICAgICAgY2FzZSAxOlxuICAgICAgICAgIGlmIChmaXJzdEJ5dGUgPCAweDgwKSB7XG4gICAgICAgICAgICBjb2RlUG9pbnQgPSBmaXJzdEJ5dGVcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHgxRikgPDwgMHg2IHwgKHNlY29uZEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweDdGKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwICYmICh0aGlyZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4QyB8IChzZWNvbmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKHRoaXJkQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0ZGICYmICh0ZW1wQ29kZVBvaW50IDwgMHhEODAwIHx8IHRlbXBDb2RlUG9pbnQgPiAweERGRkYpKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSA0OlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGZvdXJ0aEJ5dGUgPSBidWZbaSArIDNdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwICYmIChmb3VydGhCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHhGKSA8PCAweDEyIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweEMgfCAodGhpcmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKGZvdXJ0aEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweEZGRkYgJiYgdGVtcENvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGNvZGVQb2ludCA9PT0gbnVsbCkge1xuICAgICAgLy8gd2UgZGlkIG5vdCBnZW5lcmF0ZSBhIHZhbGlkIGNvZGVQb2ludCBzbyBpbnNlcnQgYVxuICAgICAgLy8gcmVwbGFjZW1lbnQgY2hhciAoVStGRkZEKSBhbmQgYWR2YW5jZSBvbmx5IDEgYnl0ZVxuICAgICAgY29kZVBvaW50ID0gMHhGRkZEXG4gICAgICBieXRlc1BlclNlcXVlbmNlID0gMVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50ID4gMHhGRkZGKSB7XG4gICAgICAvLyBlbmNvZGUgdG8gdXRmMTYgKHN1cnJvZ2F0ZSBwYWlyIGRhbmNlKVxuICAgICAgY29kZVBvaW50IC09IDB4MTAwMDBcbiAgICAgIHJlcy5wdXNoKGNvZGVQb2ludCA+Pj4gMTAgJiAweDNGRiB8IDB4RDgwMClcbiAgICAgIGNvZGVQb2ludCA9IDB4REMwMCB8IGNvZGVQb2ludCAmIDB4M0ZGXG4gICAgfVxuXG4gICAgcmVzLnB1c2goY29kZVBvaW50KVxuICAgIGkgKz0gYnl0ZXNQZXJTZXF1ZW5jZVxuICB9XG5cbiAgcmV0dXJuIGRlY29kZUNvZGVQb2ludHNBcnJheShyZXMpXG59XG5cbi8vIEJhc2VkIG9uIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzIyNzQ3MjcyLzY4MDc0MiwgdGhlIGJyb3dzZXIgd2l0aFxuLy8gdGhlIGxvd2VzdCBsaW1pdCBpcyBDaHJvbWUsIHdpdGggMHgxMDAwMCBhcmdzLlxuLy8gV2UgZ28gMSBtYWduaXR1ZGUgbGVzcywgZm9yIHNhZmV0eVxudmFyIE1BWF9BUkdVTUVOVFNfTEVOR1RIID0gMHgxMDAwXG5cbmZ1bmN0aW9uIGRlY29kZUNvZGVQb2ludHNBcnJheSAoY29kZVBvaW50cykge1xuICB2YXIgbGVuID0gY29kZVBvaW50cy5sZW5ndGhcbiAgaWYgKGxlbiA8PSBNQVhfQVJHVU1FTlRTX0xFTkdUSCkge1xuICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFN0cmluZywgY29kZVBvaW50cykgLy8gYXZvaWQgZXh0cmEgc2xpY2UoKVxuICB9XG5cbiAgLy8gRGVjb2RlIGluIGNodW5rcyB0byBhdm9pZCBcImNhbGwgc3RhY2sgc2l6ZSBleGNlZWRlZFwiLlxuICB2YXIgcmVzID0gJydcbiAgdmFyIGkgPSAwXG4gIHdoaWxlIChpIDwgbGVuKSB7XG4gICAgcmVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoXG4gICAgICBTdHJpbmcsXG4gICAgICBjb2RlUG9pbnRzLnNsaWNlKGksIGkgKz0gTUFYX0FSR1VNRU5UU19MRU5HVEgpXG4gICAgKVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0gJiAweDdGKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gYmluYXJ5U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgcmV0ID0gJydcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgcmV0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnVmW2ldKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gaGV4U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gYnVmLmxlbmd0aFxuXG4gIGlmICghc3RhcnQgfHwgc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgfHwgZW5kIDwgMCB8fCBlbmQgPiBsZW4pIGVuZCA9IGxlblxuXG4gIHZhciBvdXQgPSAnJ1xuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIG91dCArPSB0b0hleChidWZbaV0pXG4gIH1cbiAgcmV0dXJuIG91dFxufVxuXG5mdW5jdGlvbiB1dGYxNmxlU2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgYnl0ZXMgPSBidWYuc2xpY2Uoc3RhcnQsIGVuZClcbiAgdmFyIHJlcyA9ICcnXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShieXRlc1tpXSArIGJ5dGVzW2kgKyAxXSAqIDI1NilcbiAgfVxuICByZXR1cm4gcmVzXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuc2xpY2UgPSBmdW5jdGlvbiBzbGljZSAoc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gdGhpcy5sZW5ndGhcbiAgc3RhcnQgPSB+fnN0YXJ0XG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkID8gbGVuIDogfn5lbmRcblxuICBpZiAoc3RhcnQgPCAwKSB7XG4gICAgc3RhcnQgKz0gbGVuXG4gICAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIH0gZWxzZSBpZiAoc3RhcnQgPiBsZW4pIHtcbiAgICBzdGFydCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IDApIHtcbiAgICBlbmQgKz0gbGVuXG4gICAgaWYgKGVuZCA8IDApIGVuZCA9IDBcbiAgfSBlbHNlIGlmIChlbmQgPiBsZW4pIHtcbiAgICBlbmQgPSBsZW5cbiAgfVxuXG4gIGlmIChlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICB2YXIgbmV3QnVmXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIG5ld0J1ZiA9IEJ1ZmZlci5fYXVnbWVudCh0aGlzLnN1YmFycmF5KHN0YXJ0LCBlbmQpKVxuICB9IGVsc2Uge1xuICAgIHZhciBzbGljZUxlbiA9IGVuZCAtIHN0YXJ0XG4gICAgbmV3QnVmID0gbmV3IEJ1ZmZlcihzbGljZUxlbiwgdW5kZWZpbmVkKVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2xpY2VMZW47IGkrKykge1xuICAgICAgbmV3QnVmW2ldID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9XG5cbiAgaWYgKG5ld0J1Zi5sZW5ndGgpIG5ld0J1Zi5wYXJlbnQgPSB0aGlzLnBhcmVudCB8fCB0aGlzXG5cbiAgcmV0dXJuIG5ld0J1ZlxufVxuXG4vKlxuICogTmVlZCB0byBtYWtlIHN1cmUgdGhhdCBidWZmZXIgaXNuJ3QgdHJ5aW5nIHRvIHdyaXRlIG91dCBvZiBib3VuZHMuXG4gKi9cbmZ1bmN0aW9uIGNoZWNrT2Zmc2V0IChvZmZzZXQsIGV4dCwgbGVuZ3RoKSB7XG4gIGlmICgob2Zmc2V0ICUgMSkgIT09IDAgfHwgb2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ29mZnNldCBpcyBub3QgdWludCcpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBsZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdUcnlpbmcgdG8gYWNjZXNzIGJleW9uZCBidWZmZXIgbGVuZ3RoJylcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludExFID0gZnVuY3Rpb24gcmVhZFVJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludEJFID0gZnVuY3Rpb24gcmVhZFVJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcbiAgfVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIC0tYnl0ZUxlbmd0aF1cbiAgdmFyIG11bCA9IDFcbiAgd2hpbGUgKGJ5dGVMZW5ndGggPiAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50OCA9IGZ1bmN0aW9uIHJlYWRVSW50OCAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDEsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gdGhpc1tvZmZzZXRdXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkxFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MTZCRSA9IGZ1bmN0aW9uIHJlYWRVSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCA4KSB8IHRoaXNbb2Zmc2V0ICsgMV1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyTEUgPSBmdW5jdGlvbiByZWFkVUludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKCh0aGlzW29mZnNldF0pIHxcbiAgICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAgICh0aGlzW29mZnNldCArIDJdIDw8IDE2KSkgK1xuICAgICAgKHRoaXNbb2Zmc2V0ICsgM10gKiAweDEwMDAwMDApXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQzMkJFID0gZnVuY3Rpb24gcmVhZFVJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gKiAweDEwMDAwMDApICtcbiAgICAoKHRoaXNbb2Zmc2V0ICsgMV0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCA4KSB8XG4gICAgdGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50TEUgPSBmdW5jdGlvbiByZWFkSW50TEUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIGldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50QkUgPSBmdW5jdGlvbiByZWFkSW50QkUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgaSA9IGJ5dGVMZW5ndGhcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1pXVxuICB3aGlsZSAoaSA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50OCA9IGZ1bmN0aW9uIHJlYWRJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIGlmICghKHRoaXNbb2Zmc2V0XSAmIDB4ODApKSByZXR1cm4gKHRoaXNbb2Zmc2V0XSlcbiAgcmV0dXJuICgoMHhmZiAtIHRoaXNbb2Zmc2V0XSArIDEpICogLTEpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2TEUgPSBmdW5jdGlvbiByZWFkSW50MTZMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdIHwgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQxNkJFID0gZnVuY3Rpb24gcmVhZEludDE2QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgMV0gfCAodGhpc1tvZmZzZXRdIDw8IDgpXG4gIHJldHVybiAodmFsICYgMHg4MDAwKSA/IHZhbCB8IDB4RkZGRjAwMDAgOiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0pIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSA8PCAyNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJCRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gPDwgMjQpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRMRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdExFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRCRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdEJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCBmYWxzZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUxFID0gZnVuY3Rpb24gcmVhZERvdWJsZUxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgOCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCA1MiwgOClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlQkUgPSBmdW5jdGlvbiByZWFkRG91YmxlQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCA1MiwgOClcbn1cblxuZnVuY3Rpb24gY2hlY2tJbnQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihidWYpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdidWZmZXIgbXVzdCBiZSBhIEJ1ZmZlciBpbnN0YW5jZScpXG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3ZhbHVlIGlzIG91dCBvZiBib3VuZHMnKVxuICBpZiAob2Zmc2V0ICsgZXh0ID4gYnVmLmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB0aGlzW29mZnNldF0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50QkUgPSBmdW5jdGlvbiB3cml0ZVVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aCAtIDFcbiAgdmFyIG11bCA9IDFcbiAgdGhpc1tvZmZzZXQgKyBpXSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoLS1pID49IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50OCA9IGZ1bmN0aW9uIHdyaXRlVUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHhmZiwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkgdmFsdWUgPSBNYXRoLmZsb29yKHZhbHVlKVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQxNiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmYgKyB2YWx1ZSArIDFcbiAgZm9yICh2YXIgaSA9IDAsIGogPSBNYXRoLm1pbihidWYubGVuZ3RoIC0gb2Zmc2V0LCAyKTsgaSA8IGo7IGkrKykge1xuICAgIGJ1ZltvZmZzZXQgKyBpXSA9ICh2YWx1ZSAmICgweGZmIDw8ICg4ICogKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkpKSkgPj4+XG4gICAgICAobGl0dGxlRW5kaWFuID8gaSA6IDEgLSBpKSAqIDhcbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDE2TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4ZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQzMiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgNCk7IGkgPCBqOyBpKyspIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgPj4+IChsaXR0bGVFbmRpYW4gPyBpIDogMyAtIGkpICogOCkgJiAweGZmXG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDMyQkUgPSBmdW5jdGlvbiB3cml0ZVVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4ZmZmZmZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50TEUgPSBmdW5jdGlvbiB3cml0ZUludExFICh2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbGltaXQgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCAtIDEpXG5cbiAgICBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBsaW1pdCAtIDEsIC1saW1pdClcbiAgfVxuXG4gIHZhciBpID0gMFxuICB2YXIgbXVsID0gMVxuICB2YXIgc3ViID0gdmFsdWUgPCAwID8gMSA6IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludEJFID0gZnVuY3Rpb24gd3JpdGVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSB2YWx1ZSA8IDAgPyAxIDogMFxuICB0aGlzW29mZnNldCArIGldID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgtLWkgPj0gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAoKHZhbHVlIC8gbXVsKSA+PiAwKSAtIHN1YiAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQ4ID0gZnVuY3Rpb24gd3JpdGVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4N2YsIC0weDgwKVxuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB2YWx1ZSA9IE1hdGguZmxvb3IodmFsdWUpXG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZiArIHZhbHVlICsgMVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MTZMRSA9IGZ1bmN0aW9uIHdyaXRlSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweDdmZmYsIC0weDgwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MzJCRSA9IGZ1bmN0aW9uIHdyaXRlSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweDdmZmZmZmZmLCAtMHg4MDAwMDAwMClcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5mdW5jdGlvbiBjaGVja0lFRUU3NTQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAodmFsdWUgPiBtYXggfHwgdmFsdWUgPCBtaW4pIHRocm93IG5ldyBSYW5nZUVycm9yKCd2YWx1ZSBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxuICBpZiAob2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRmxvYXQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgNCwgMy40MDI4MjM0NjYzODUyODg2ZSszOCwgLTMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgMjMsIDQpXG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdExFID0gZnVuY3Rpb24gd3JpdGVGbG9hdExFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUZsb2F0QkUgPSBmdW5jdGlvbiB3cml0ZUZsb2F0QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZUZsb2F0KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuZnVuY3Rpb24gd3JpdGVEb3VibGUgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgOCwgMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgsIC0xLjc5NzY5MzEzNDg2MjMxNTdFKzMwOClcbiAgfVxuICBpZWVlNzU0LndyaXRlKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCA1MiwgOClcbiAgcmV0dXJuIG9mZnNldCArIDhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUxFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUsIG5vQXNzZXJ0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRG91YmxlQkUgPSBmdW5jdGlvbiB3cml0ZURvdWJsZUJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVEb3VibGUodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UsIG5vQXNzZXJ0KVxufVxuXG4vLyBjb3B5KHRhcmdldEJ1ZmZlciwgdGFyZ2V0U3RhcnQ9MCwgc291cmNlU3RhcnQ9MCwgc291cmNlRW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmNvcHkgPSBmdW5jdGlvbiBjb3B5ICh0YXJnZXQsIHRhcmdldFN0YXJ0LCBzdGFydCwgZW5kKSB7XG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCAmJiBlbmQgIT09IDApIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmICh0YXJnZXRTdGFydCA+PSB0YXJnZXQubGVuZ3RoKSB0YXJnZXRTdGFydCA9IHRhcmdldC5sZW5ndGhcbiAgaWYgKCF0YXJnZXRTdGFydCkgdGFyZ2V0U3RhcnQgPSAwXG4gIGlmIChlbmQgPiAwICYmIGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIC8vIENvcHkgMCBieXRlczsgd2UncmUgZG9uZVxuICBpZiAoZW5kID09PSBzdGFydCkgcmV0dXJuIDBcbiAgaWYgKHRhcmdldC5sZW5ndGggPT09IDAgfHwgdGhpcy5sZW5ndGggPT09IDApIHJldHVybiAwXG5cbiAgLy8gRmF0YWwgZXJyb3IgY29uZGl0aW9uc1xuICBpZiAodGFyZ2V0U3RhcnQgPCAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3RhcmdldFN0YXJ0IG91dCBvZiBib3VuZHMnKVxuICB9XG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VFbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgLy8gQXJlIHdlIG9vYj9cbiAgaWYgKGVuZCA+IHRoaXMubGVuZ3RoKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0IDwgZW5kIC0gc3RhcnQpIHtcbiAgICBlbmQgPSB0YXJnZXQubGVuZ3RoIC0gdGFyZ2V0U3RhcnQgKyBzdGFydFxuICB9XG5cbiAgdmFyIGxlbiA9IGVuZCAtIHN0YXJ0XG4gIHZhciBpXG5cbiAgaWYgKHRoaXMgPT09IHRhcmdldCAmJiBzdGFydCA8IHRhcmdldFN0YXJ0ICYmIHRhcmdldFN0YXJ0IDwgZW5kKSB7XG4gICAgLy8gZGVzY2VuZGluZyBjb3B5IGZyb20gZW5kXG4gICAgZm9yIChpID0gbGVuIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2UgaWYgKGxlbiA8IDEwMDAgfHwgIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gYXNjZW5kaW5nIGNvcHkgZnJvbSBzdGFydFxuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgdGFyZ2V0W2kgKyB0YXJnZXRTdGFydF0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGFyZ2V0Ll9zZXQodGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLCB0YXJnZXRTdGFydClcbiAgfVxuXG4gIHJldHVybiBsZW5cbn1cblxuLy8gZmlsbCh2YWx1ZSwgc3RhcnQ9MCwgZW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmZpbGwgPSBmdW5jdGlvbiBmaWxsICh2YWx1ZSwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXZhbHVlKSB2YWx1ZSA9IDBcbiAgaWYgKCFzdGFydCkgc3RhcnQgPSAwXG4gIGlmICghZW5kKSBlbmQgPSB0aGlzLmxlbmd0aFxuXG4gIGlmIChlbmQgPCBzdGFydCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2VuZCA8IHN0YXJ0JylcblxuICAvLyBGaWxsIDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVyblxuICBpZiAodGhpcy5sZW5ndGggPT09IDApIHJldHVyblxuXG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDAgfHwgZW5kID4gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdlbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgdmFyIGlcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICBmb3IgKGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgICB0aGlzW2ldID0gdmFsdWVcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFyIGJ5dGVzID0gdXRmOFRvQnl0ZXModmFsdWUudG9TdHJpbmcoKSlcbiAgICB2YXIgbGVuID0gYnl0ZXMubGVuZ3RoXG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdGhpc1tpXSA9IGJ5dGVzW2kgJSBsZW5dXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXNcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IGBBcnJheUJ1ZmZlcmAgd2l0aCB0aGUgKmNvcGllZCogbWVtb3J5IG9mIHRoZSBidWZmZXIgaW5zdGFuY2UuXG4gKiBBZGRlZCBpbiBOb2RlIDAuMTIuIE9ubHkgYXZhaWxhYmxlIGluIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCBBcnJheUJ1ZmZlci5cbiAqL1xuQnVmZmVyLnByb3RvdHlwZS50b0FycmF5QnVmZmVyID0gZnVuY3Rpb24gdG9BcnJheUJ1ZmZlciAoKSB7XG4gIGlmICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAgIHJldHVybiAobmV3IEJ1ZmZlcih0aGlzKSkuYnVmZmVyXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBidWYgPSBuZXcgVWludDhBcnJheSh0aGlzLmxlbmd0aClcbiAgICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBidWYubGVuZ3RoOyBpIDwgbGVuOyBpICs9IDEpIHtcbiAgICAgICAgYnVmW2ldID0gdGhpc1tpXVxuICAgICAgfVxuICAgICAgcmV0dXJuIGJ1Zi5idWZmZXJcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQnVmZmVyLnRvQXJyYXlCdWZmZXIgbm90IHN1cHBvcnRlZCBpbiB0aGlzIGJyb3dzZXInKVxuICB9XG59XG5cbi8vIEhFTFBFUiBGVU5DVElPTlNcbi8vID09PT09PT09PT09PT09PT1cblxudmFyIEJQID0gQnVmZmVyLnByb3RvdHlwZVxuXG4vKipcbiAqIEF1Z21lbnQgYSBVaW50OEFycmF5ICppbnN0YW5jZSogKG5vdCB0aGUgVWludDhBcnJheSBjbGFzcyEpIHdpdGggQnVmZmVyIG1ldGhvZHNcbiAqL1xuQnVmZmVyLl9hdWdtZW50ID0gZnVuY3Rpb24gX2F1Z21lbnQgKGFycikge1xuICBhcnIuY29uc3RydWN0b3IgPSBCdWZmZXJcbiAgYXJyLl9pc0J1ZmZlciA9IHRydWVcblxuICAvLyBzYXZlIHJlZmVyZW5jZSB0byBvcmlnaW5hbCBVaW50OEFycmF5IHNldCBtZXRob2QgYmVmb3JlIG92ZXJ3cml0aW5nXG4gIGFyci5fc2V0ID0gYXJyLnNldFxuXG4gIC8vIGRlcHJlY2F0ZWRcbiAgYXJyLmdldCA9IEJQLmdldFxuICBhcnIuc2V0ID0gQlAuc2V0XG5cbiAgYXJyLndyaXRlID0gQlAud3JpdGVcbiAgYXJyLnRvU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvTG9jYWxlU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvSlNPTiA9IEJQLnRvSlNPTlxuICBhcnIuZXF1YWxzID0gQlAuZXF1YWxzXG4gIGFyci5jb21wYXJlID0gQlAuY29tcGFyZVxuICBhcnIuaW5kZXhPZiA9IEJQLmluZGV4T2ZcbiAgYXJyLmNvcHkgPSBCUC5jb3B5XG4gIGFyci5zbGljZSA9IEJQLnNsaWNlXG4gIGFyci5yZWFkVUludExFID0gQlAucmVhZFVJbnRMRVxuICBhcnIucmVhZFVJbnRCRSA9IEJQLnJlYWRVSW50QkVcbiAgYXJyLnJlYWRVSW50OCA9IEJQLnJlYWRVSW50OFxuICBhcnIucmVhZFVJbnQxNkxFID0gQlAucmVhZFVJbnQxNkxFXG4gIGFyci5yZWFkVUludDE2QkUgPSBCUC5yZWFkVUludDE2QkVcbiAgYXJyLnJlYWRVSW50MzJMRSA9IEJQLnJlYWRVSW50MzJMRVxuICBhcnIucmVhZFVJbnQzMkJFID0gQlAucmVhZFVJbnQzMkJFXG4gIGFyci5yZWFkSW50TEUgPSBCUC5yZWFkSW50TEVcbiAgYXJyLnJlYWRJbnRCRSA9IEJQLnJlYWRJbnRCRVxuICBhcnIucmVhZEludDggPSBCUC5yZWFkSW50OFxuICBhcnIucmVhZEludDE2TEUgPSBCUC5yZWFkSW50MTZMRVxuICBhcnIucmVhZEludDE2QkUgPSBCUC5yZWFkSW50MTZCRVxuICBhcnIucmVhZEludDMyTEUgPSBCUC5yZWFkSW50MzJMRVxuICBhcnIucmVhZEludDMyQkUgPSBCUC5yZWFkSW50MzJCRVxuICBhcnIucmVhZEZsb2F0TEUgPSBCUC5yZWFkRmxvYXRMRVxuICBhcnIucmVhZEZsb2F0QkUgPSBCUC5yZWFkRmxvYXRCRVxuICBhcnIucmVhZERvdWJsZUxFID0gQlAucmVhZERvdWJsZUxFXG4gIGFyci5yZWFkRG91YmxlQkUgPSBCUC5yZWFkRG91YmxlQkVcbiAgYXJyLndyaXRlVUludDggPSBCUC53cml0ZVVJbnQ4XG4gIGFyci53cml0ZVVJbnRMRSA9IEJQLndyaXRlVUludExFXG4gIGFyci53cml0ZVVJbnRCRSA9IEJQLndyaXRlVUludEJFXG4gIGFyci53cml0ZVVJbnQxNkxFID0gQlAud3JpdGVVSW50MTZMRVxuICBhcnIud3JpdGVVSW50MTZCRSA9IEJQLndyaXRlVUludDE2QkVcbiAgYXJyLndyaXRlVUludDMyTEUgPSBCUC53cml0ZVVJbnQzMkxFXG4gIGFyci53cml0ZVVJbnQzMkJFID0gQlAud3JpdGVVSW50MzJCRVxuICBhcnIud3JpdGVJbnRMRSA9IEJQLndyaXRlSW50TEVcbiAgYXJyLndyaXRlSW50QkUgPSBCUC53cml0ZUludEJFXG4gIGFyci53cml0ZUludDggPSBCUC53cml0ZUludDhcbiAgYXJyLndyaXRlSW50MTZMRSA9IEJQLndyaXRlSW50MTZMRVxuICBhcnIud3JpdGVJbnQxNkJFID0gQlAud3JpdGVJbnQxNkJFXG4gIGFyci53cml0ZUludDMyTEUgPSBCUC53cml0ZUludDMyTEVcbiAgYXJyLndyaXRlSW50MzJCRSA9IEJQLndyaXRlSW50MzJCRVxuICBhcnIud3JpdGVGbG9hdExFID0gQlAud3JpdGVGbG9hdExFXG4gIGFyci53cml0ZUZsb2F0QkUgPSBCUC53cml0ZUZsb2F0QkVcbiAgYXJyLndyaXRlRG91YmxlTEUgPSBCUC53cml0ZURvdWJsZUxFXG4gIGFyci53cml0ZURvdWJsZUJFID0gQlAud3JpdGVEb3VibGVCRVxuICBhcnIuZmlsbCA9IEJQLmZpbGxcbiAgYXJyLmluc3BlY3QgPSBCUC5pbnNwZWN0XG4gIGFyci50b0FycmF5QnVmZmVyID0gQlAudG9BcnJheUJ1ZmZlclxuXG4gIHJldHVybiBhcnJcbn1cblxudmFyIElOVkFMSURfQkFTRTY0X1JFID0gL1teK1xcLzAtOUEtWmEtei1fXS9nXG5cbmZ1bmN0aW9uIGJhc2U2NGNsZWFuIChzdHIpIHtcbiAgLy8gTm9kZSBzdHJpcHMgb3V0IGludmFsaWQgY2hhcmFjdGVycyBsaWtlIFxcbiBhbmQgXFx0IGZyb20gdGhlIHN0cmluZywgYmFzZTY0LWpzIGRvZXMgbm90XG4gIHN0ciA9IHN0cmluZ3RyaW0oc3RyKS5yZXBsYWNlKElOVkFMSURfQkFTRTY0X1JFLCAnJylcbiAgLy8gTm9kZSBjb252ZXJ0cyBzdHJpbmdzIHdpdGggbGVuZ3RoIDwgMiB0byAnJ1xuICBpZiAoc3RyLmxlbmd0aCA8IDIpIHJldHVybiAnJ1xuICAvLyBOb2RlIGFsbG93cyBmb3Igbm9uLXBhZGRlZCBiYXNlNjQgc3RyaW5ncyAobWlzc2luZyB0cmFpbGluZyA9PT0pLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgd2hpbGUgKHN0ci5sZW5ndGggJSA0ICE9PSAwKSB7XG4gICAgc3RyID0gc3RyICsgJz0nXG4gIH1cbiAgcmV0dXJuIHN0clxufVxuXG5mdW5jdGlvbiBzdHJpbmd0cmltIChzdHIpIHtcbiAgaWYgKHN0ci50cmltKSByZXR1cm4gc3RyLnRyaW0oKVxuICByZXR1cm4gc3RyLnJlcGxhY2UoL15cXHMrfFxccyskL2csICcnKVxufVxuXG5mdW5jdGlvbiB0b0hleCAobikge1xuICBpZiAobiA8IDE2KSByZXR1cm4gJzAnICsgbi50b1N0cmluZygxNilcbiAgcmV0dXJuIG4udG9TdHJpbmcoMTYpXG59XG5cbmZ1bmN0aW9uIHV0ZjhUb0J5dGVzIChzdHJpbmcsIHVuaXRzKSB7XG4gIHVuaXRzID0gdW5pdHMgfHwgSW5maW5pdHlcbiAgdmFyIGNvZGVQb2ludFxuICB2YXIgbGVuZ3RoID0gc3RyaW5nLmxlbmd0aFxuICB2YXIgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcbiAgdmFyIGJ5dGVzID0gW11cblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgY29kZVBvaW50ID0gc3RyaW5nLmNoYXJDb2RlQXQoaSlcblxuICAgIC8vIGlzIHN1cnJvZ2F0ZSBjb21wb25lbnRcbiAgICBpZiAoY29kZVBvaW50ID4gMHhEN0ZGICYmIGNvZGVQb2ludCA8IDB4RTAwMCkge1xuICAgICAgLy8gbGFzdCBjaGFyIHdhcyBhIGxlYWRcbiAgICAgIGlmICghbGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgICAvLyBubyBsZWFkIHlldFxuICAgICAgICBpZiAoY29kZVBvaW50ID4gMHhEQkZGKSB7XG4gICAgICAgICAgLy8gdW5leHBlY3RlZCB0cmFpbFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH0gZWxzZSBpZiAoaSArIDEgPT09IGxlbmd0aCkge1xuICAgICAgICAgIC8vIHVucGFpcmVkIGxlYWRcbiAgICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gdmFsaWQgbGVhZFxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG5cbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gMiBsZWFkcyBpbiBhIHJvd1xuICAgICAgaWYgKGNvZGVQb2ludCA8IDB4REMwMCkge1xuICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgbGVhZFN1cnJvZ2F0ZSA9IGNvZGVQb2ludFxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyB2YWxpZCBzdXJyb2dhdGUgcGFpclxuICAgICAgY29kZVBvaW50ID0gKGxlYWRTdXJyb2dhdGUgLSAweEQ4MDAgPDwgMTAgfCBjb2RlUG9pbnQgLSAweERDMDApICsgMHgxMDAwMFxuICAgIH0gZWxzZSBpZiAobGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgLy8gdmFsaWQgYm1wIGNoYXIsIGJ1dCBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgfVxuXG4gICAgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcblxuICAgIC8vIGVuY29kZSB1dGY4XG4gICAgaWYgKGNvZGVQb2ludCA8IDB4ODApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMSkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChjb2RlUG9pbnQpXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDgwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAyKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2IHwgMHhDMCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMykgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyB8IDB4RTAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDQpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDEyIHwgMHhGMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2ICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjb2RlIHBvaW50JylcbiAgICB9XG4gIH1cblxuICByZXR1cm4gYnl0ZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlUb0J5dGVzIChzdHIpIHtcbiAgdmFyIGJ5dGVBcnJheSA9IFtdXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgLy8gTm9kZSdzIGNvZGUgc2VlbXMgdG8gYmUgZG9pbmcgdGhpcyBhbmQgbm90ICYgMHg3Ri4uXG4gICAgYnl0ZUFycmF5LnB1c2goc3RyLmNoYXJDb2RlQXQoaSkgJiAweEZGKVxuICB9XG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gdXRmMTZsZVRvQnl0ZXMgKHN0ciwgdW5pdHMpIHtcbiAgdmFyIGMsIGhpLCBsb1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcblxuICAgIGMgPSBzdHIuY2hhckNvZGVBdChpKVxuICAgIGhpID0gYyA+PiA4XG4gICAgbG8gPSBjICUgMjU2XG4gICAgYnl0ZUFycmF5LnB1c2gobG8pXG4gICAgYnl0ZUFycmF5LnB1c2goaGkpXG4gIH1cblxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIGJhc2U2NFRvQnl0ZXMgKHN0cikge1xuICByZXR1cm4gYmFzZTY0LnRvQnl0ZUFycmF5KGJhc2U2NGNsZWFuKHN0cikpXG59XG5cbmZ1bmN0aW9uIGJsaXRCdWZmZXIgKHNyYywgZHN0LCBvZmZzZXQsIGxlbmd0aCkge1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKChpICsgb2Zmc2V0ID49IGRzdC5sZW5ndGgpIHx8IChpID49IHNyYy5sZW5ndGgpKSBicmVha1xuICAgIGRzdFtpICsgb2Zmc2V0XSA9IHNyY1tpXVxuICB9XG4gIHJldHVybiBpXG59XG4iLCJ2YXIgbG9va3VwID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky8nO1xuXG47KGZ1bmN0aW9uIChleHBvcnRzKSB7XG5cdCd1c2Ugc3RyaWN0JztcblxuICB2YXIgQXJyID0gKHR5cGVvZiBVaW50OEFycmF5ICE9PSAndW5kZWZpbmVkJylcbiAgICA/IFVpbnQ4QXJyYXlcbiAgICA6IEFycmF5XG5cblx0dmFyIFBMVVMgICA9ICcrJy5jaGFyQ29kZUF0KDApXG5cdHZhciBTTEFTSCAgPSAnLycuY2hhckNvZGVBdCgwKVxuXHR2YXIgTlVNQkVSID0gJzAnLmNoYXJDb2RlQXQoMClcblx0dmFyIExPV0VSICA9ICdhJy5jaGFyQ29kZUF0KDApXG5cdHZhciBVUFBFUiAgPSAnQScuY2hhckNvZGVBdCgwKVxuXHR2YXIgUExVU19VUkxfU0FGRSA9ICctJy5jaGFyQ29kZUF0KDApXG5cdHZhciBTTEFTSF9VUkxfU0FGRSA9ICdfJy5jaGFyQ29kZUF0KDApXG5cblx0ZnVuY3Rpb24gZGVjb2RlIChlbHQpIHtcblx0XHR2YXIgY29kZSA9IGVsdC5jaGFyQ29kZUF0KDApXG5cdFx0aWYgKGNvZGUgPT09IFBMVVMgfHxcblx0XHQgICAgY29kZSA9PT0gUExVU19VUkxfU0FGRSlcblx0XHRcdHJldHVybiA2MiAvLyAnKydcblx0XHRpZiAoY29kZSA9PT0gU0xBU0ggfHxcblx0XHQgICAgY29kZSA9PT0gU0xBU0hfVVJMX1NBRkUpXG5cdFx0XHRyZXR1cm4gNjMgLy8gJy8nXG5cdFx0aWYgKGNvZGUgPCBOVU1CRVIpXG5cdFx0XHRyZXR1cm4gLTEgLy9ubyBtYXRjaFxuXHRcdGlmIChjb2RlIDwgTlVNQkVSICsgMTApXG5cdFx0XHRyZXR1cm4gY29kZSAtIE5VTUJFUiArIDI2ICsgMjZcblx0XHRpZiAoY29kZSA8IFVQUEVSICsgMjYpXG5cdFx0XHRyZXR1cm4gY29kZSAtIFVQUEVSXG5cdFx0aWYgKGNvZGUgPCBMT1dFUiArIDI2KVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBMT1dFUiArIDI2XG5cdH1cblxuXHRmdW5jdGlvbiBiNjRUb0J5dGVBcnJheSAoYjY0KSB7XG5cdFx0dmFyIGksIGosIGwsIHRtcCwgcGxhY2VIb2xkZXJzLCBhcnJcblxuXHRcdGlmIChiNjQubGVuZ3RoICUgNCA+IDApIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzdHJpbmcuIExlbmd0aCBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgNCcpXG5cdFx0fVxuXG5cdFx0Ly8gdGhlIG51bWJlciBvZiBlcXVhbCBzaWducyAocGxhY2UgaG9sZGVycylcblx0XHQvLyBpZiB0aGVyZSBhcmUgdHdvIHBsYWNlaG9sZGVycywgdGhhbiB0aGUgdHdvIGNoYXJhY3RlcnMgYmVmb3JlIGl0XG5cdFx0Ly8gcmVwcmVzZW50IG9uZSBieXRlXG5cdFx0Ly8gaWYgdGhlcmUgaXMgb25seSBvbmUsIHRoZW4gdGhlIHRocmVlIGNoYXJhY3RlcnMgYmVmb3JlIGl0IHJlcHJlc2VudCAyIGJ5dGVzXG5cdFx0Ly8gdGhpcyBpcyBqdXN0IGEgY2hlYXAgaGFjayB0byBub3QgZG8gaW5kZXhPZiB0d2ljZVxuXHRcdHZhciBsZW4gPSBiNjQubGVuZ3RoXG5cdFx0cGxhY2VIb2xkZXJzID0gJz0nID09PSBiNjQuY2hhckF0KGxlbiAtIDIpID8gMiA6ICc9JyA9PT0gYjY0LmNoYXJBdChsZW4gLSAxKSA/IDEgOiAwXG5cblx0XHQvLyBiYXNlNjQgaXMgNC8zICsgdXAgdG8gdHdvIGNoYXJhY3RlcnMgb2YgdGhlIG9yaWdpbmFsIGRhdGFcblx0XHRhcnIgPSBuZXcgQXJyKGI2NC5sZW5ndGggKiAzIC8gNCAtIHBsYWNlSG9sZGVycylcblxuXHRcdC8vIGlmIHRoZXJlIGFyZSBwbGFjZWhvbGRlcnMsIG9ubHkgZ2V0IHVwIHRvIHRoZSBsYXN0IGNvbXBsZXRlIDQgY2hhcnNcblx0XHRsID0gcGxhY2VIb2xkZXJzID4gMCA/IGI2NC5sZW5ndGggLSA0IDogYjY0Lmxlbmd0aFxuXG5cdFx0dmFyIEwgPSAwXG5cblx0XHRmdW5jdGlvbiBwdXNoICh2KSB7XG5cdFx0XHRhcnJbTCsrXSA9IHZcblx0XHR9XG5cblx0XHRmb3IgKGkgPSAwLCBqID0gMDsgaSA8IGw7IGkgKz0gNCwgaiArPSAzKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDE4KSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDEyKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMikpIDw8IDYpIHwgZGVjb2RlKGI2NC5jaGFyQXQoaSArIDMpKVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwMDApID4+IDE2KVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwKSA+PiA4KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH1cblxuXHRcdGlmIChwbGFjZUhvbGRlcnMgPT09IDIpIHtcblx0XHRcdHRtcCA9IChkZWNvZGUoYjY0LmNoYXJBdChpKSkgPDwgMikgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA+PiA0KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH0gZWxzZSBpZiAocGxhY2VIb2xkZXJzID09PSAxKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDEwKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDQpIHwgKGRlY29kZShiNjQuY2hhckF0KGkgKyAyKSkgPj4gMilcblx0XHRcdHB1c2goKHRtcCA+PiA4KSAmIDB4RkYpXG5cdFx0XHRwdXNoKHRtcCAmIDB4RkYpXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGFyclxuXHR9XG5cblx0ZnVuY3Rpb24gdWludDhUb0Jhc2U2NCAodWludDgpIHtcblx0XHR2YXIgaSxcblx0XHRcdGV4dHJhQnl0ZXMgPSB1aW50OC5sZW5ndGggJSAzLCAvLyBpZiB3ZSBoYXZlIDEgYnl0ZSBsZWZ0LCBwYWQgMiBieXRlc1xuXHRcdFx0b3V0cHV0ID0gXCJcIixcblx0XHRcdHRlbXAsIGxlbmd0aFxuXG5cdFx0ZnVuY3Rpb24gZW5jb2RlIChudW0pIHtcblx0XHRcdHJldHVybiBsb29rdXAuY2hhckF0KG51bSlcblx0XHR9XG5cblx0XHRmdW5jdGlvbiB0cmlwbGV0VG9CYXNlNjQgKG51bSkge1xuXHRcdFx0cmV0dXJuIGVuY29kZShudW0gPj4gMTggJiAweDNGKSArIGVuY29kZShudW0gPj4gMTIgJiAweDNGKSArIGVuY29kZShudW0gPj4gNiAmIDB4M0YpICsgZW5jb2RlKG51bSAmIDB4M0YpXG5cdFx0fVxuXG5cdFx0Ly8gZ28gdGhyb3VnaCB0aGUgYXJyYXkgZXZlcnkgdGhyZWUgYnl0ZXMsIHdlJ2xsIGRlYWwgd2l0aCB0cmFpbGluZyBzdHVmZiBsYXRlclxuXHRcdGZvciAoaSA9IDAsIGxlbmd0aCA9IHVpbnQ4Lmxlbmd0aCAtIGV4dHJhQnl0ZXM7IGkgPCBsZW5ndGg7IGkgKz0gMykge1xuXHRcdFx0dGVtcCA9ICh1aW50OFtpXSA8PCAxNikgKyAodWludDhbaSArIDFdIDw8IDgpICsgKHVpbnQ4W2kgKyAyXSlcblx0XHRcdG91dHB1dCArPSB0cmlwbGV0VG9CYXNlNjQodGVtcClcblx0XHR9XG5cblx0XHQvLyBwYWQgdGhlIGVuZCB3aXRoIHplcm9zLCBidXQgbWFrZSBzdXJlIHRvIG5vdCBmb3JnZXQgdGhlIGV4dHJhIGJ5dGVzXG5cdFx0c3dpdGNoIChleHRyYUJ5dGVzKSB7XG5cdFx0XHRjYXNlIDE6XG5cdFx0XHRcdHRlbXAgPSB1aW50OFt1aW50OC5sZW5ndGggLSAxXVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKHRlbXAgPj4gMilcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA8PCA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSAnPT0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0XHRjYXNlIDI6XG5cdFx0XHRcdHRlbXAgPSAodWludDhbdWludDgubGVuZ3RoIC0gMl0gPDwgOCkgKyAodWludDhbdWludDgubGVuZ3RoIC0gMV0pXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUodGVtcCA+PiAxMClcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA+PiA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPDwgMikgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gJz0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG91dHB1dFxuXHR9XG5cblx0ZXhwb3J0cy50b0J5dGVBcnJheSA9IGI2NFRvQnl0ZUFycmF5XG5cdGV4cG9ydHMuZnJvbUJ5dGVBcnJheSA9IHVpbnQ4VG9CYXNlNjRcbn0odHlwZW9mIGV4cG9ydHMgPT09ICd1bmRlZmluZWQnID8gKHRoaXMuYmFzZTY0anMgPSB7fSkgOiBleHBvcnRzKSlcbiIsImV4cG9ydHMucmVhZCA9IGZ1bmN0aW9uIChidWZmZXIsIG9mZnNldCwgaXNMRSwgbUxlbiwgbkJ5dGVzKSB7XG4gIHZhciBlLCBtXG4gIHZhciBlTGVuID0gbkJ5dGVzICogOCAtIG1MZW4gLSAxXG4gIHZhciBlTWF4ID0gKDEgPDwgZUxlbikgLSAxXG4gIHZhciBlQmlhcyA9IGVNYXggPj4gMVxuICB2YXIgbkJpdHMgPSAtN1xuICB2YXIgaSA9IGlzTEUgPyAobkJ5dGVzIC0gMSkgOiAwXG4gIHZhciBkID0gaXNMRSA/IC0xIDogMVxuICB2YXIgcyA9IGJ1ZmZlcltvZmZzZXQgKyBpXVxuXG4gIGkgKz0gZFxuXG4gIGUgPSBzICYgKCgxIDw8ICgtbkJpdHMpKSAtIDEpXG4gIHMgPj49ICgtbkJpdHMpXG4gIG5CaXRzICs9IGVMZW5cbiAgZm9yICg7IG5CaXRzID4gMDsgZSA9IGUgKiAyNTYgKyBidWZmZXJbb2Zmc2V0ICsgaV0sIGkgKz0gZCwgbkJpdHMgLT0gOCkge31cblxuICBtID0gZSAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBlID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBtTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IG0gPSBtICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgaWYgKGUgPT09IDApIHtcbiAgICBlID0gMSAtIGVCaWFzXG4gIH0gZWxzZSBpZiAoZSA9PT0gZU1heCkge1xuICAgIHJldHVybiBtID8gTmFOIDogKChzID8gLTEgOiAxKSAqIEluZmluaXR5KVxuICB9IGVsc2Uge1xuICAgIG0gPSBtICsgTWF0aC5wb3coMiwgbUxlbilcbiAgICBlID0gZSAtIGVCaWFzXG4gIH1cbiAgcmV0dXJuIChzID8gLTEgOiAxKSAqIG0gKiBNYXRoLnBvdygyLCBlIC0gbUxlbilcbn1cblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uIChidWZmZXIsIHZhbHVlLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbSwgY1xuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIHJ0ID0gKG1MZW4gPT09IDIzID8gTWF0aC5wb3coMiwgLTI0KSAtIE1hdGgucG93KDIsIC03NykgOiAwKVxuICB2YXIgaSA9IGlzTEUgPyAwIDogKG5CeXRlcyAtIDEpXG4gIHZhciBkID0gaXNMRSA/IDEgOiAtMVxuICB2YXIgcyA9IHZhbHVlIDwgMCB8fCAodmFsdWUgPT09IDAgJiYgMSAvIHZhbHVlIDwgMCkgPyAxIDogMFxuXG4gIHZhbHVlID0gTWF0aC5hYnModmFsdWUpXG5cbiAgaWYgKGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICBtID0gaXNOYU4odmFsdWUpID8gMSA6IDBcbiAgICBlID0gZU1heFxuICB9IGVsc2Uge1xuICAgIGUgPSBNYXRoLmZsb29yKE1hdGgubG9nKHZhbHVlKSAvIE1hdGguTE4yKVxuICAgIGlmICh2YWx1ZSAqIChjID0gTWF0aC5wb3coMiwgLWUpKSA8IDEpIHtcbiAgICAgIGUtLVxuICAgICAgYyAqPSAyXG4gICAgfVxuICAgIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgdmFsdWUgKz0gcnQgLyBjXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbHVlICs9IHJ0ICogTWF0aC5wb3coMiwgMSAtIGVCaWFzKVxuICAgIH1cbiAgICBpZiAodmFsdWUgKiBjID49IDIpIHtcbiAgICAgIGUrK1xuICAgICAgYyAvPSAyXG4gICAgfVxuXG4gICAgaWYgKGUgKyBlQmlhcyA+PSBlTWF4KSB7XG4gICAgICBtID0gMFxuICAgICAgZSA9IGVNYXhcbiAgICB9IGVsc2UgaWYgKGUgKyBlQmlhcyA+PSAxKSB7XG4gICAgICBtID0gKHZhbHVlICogYyAtIDEpICogTWF0aC5wb3coMiwgbUxlbilcbiAgICAgIGUgPSBlICsgZUJpYXNcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IHZhbHVlICogTWF0aC5wb3coMiwgZUJpYXMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gMFxuICAgIH1cbiAgfVxuXG4gIGZvciAoOyBtTGVuID49IDg7IGJ1ZmZlcltvZmZzZXQgKyBpXSA9IG0gJiAweGZmLCBpICs9IGQsIG0gLz0gMjU2LCBtTGVuIC09IDgpIHt9XG5cbiAgZSA9IChlIDw8IG1MZW4pIHwgbVxuICBlTGVuICs9IG1MZW5cbiAgZm9yICg7IGVMZW4gPiAwOyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBlICYgMHhmZiwgaSArPSBkLCBlIC89IDI1NiwgZUxlbiAtPSA4KSB7fVxuXG4gIGJ1ZmZlcltvZmZzZXQgKyBpIC0gZF0gfD0gcyAqIDEyOFxufVxuIiwiXG4vKipcbiAqIGlzQXJyYXlcbiAqL1xuXG52YXIgaXNBcnJheSA9IEFycmF5LmlzQXJyYXk7XG5cbi8qKlxuICogdG9TdHJpbmdcbiAqL1xuXG52YXIgc3RyID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztcblxuLyoqXG4gKiBXaGV0aGVyIG9yIG5vdCB0aGUgZ2l2ZW4gYHZhbGBcbiAqIGlzIGFuIGFycmF5LlxuICpcbiAqIGV4YW1wbGU6XG4gKlxuICogICAgICAgIGlzQXJyYXkoW10pO1xuICogICAgICAgIC8vID4gdHJ1ZVxuICogICAgICAgIGlzQXJyYXkoYXJndW1lbnRzKTtcbiAqICAgICAgICAvLyA+IGZhbHNlXG4gKiAgICAgICAgaXNBcnJheSgnJyk7XG4gKiAgICAgICAgLy8gPiBmYWxzZVxuICpcbiAqIEBwYXJhbSB7bWl4ZWR9IHZhbFxuICogQHJldHVybiB7Ym9vbH1cbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGlzQXJyYXkgfHwgZnVuY3Rpb24gKHZhbCkge1xuICByZXR1cm4gISEgdmFsICYmICdbb2JqZWN0IEFycmF5XScgPT0gc3RyLmNhbGwodmFsKTtcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJ2ZXJzaW9uXCI6IFwiXCJcbn1cbiIsIi8qKlxuICogRXBpY2VudGVyIEphdmFzY3JpcHQgbGlicmFyaWVzXG4gKiB2PCU9IHZlcnNpb24gJT5cbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9mb3Jpby9lcGljZW50ZXItanMtbGlic1xuICovXG5cbnZhciBGID0ge1xuICAgIHV0aWw6IHt9LFxuICAgIGZhY3Rvcnk6IHt9LFxuICAgIHRyYW5zcG9ydDoge30sXG4gICAgc3RvcmU6IHt9LFxuICAgIHNlcnZpY2U6IHt9LFxuICAgIG1hbmFnZXI6IHtcbiAgICAgICAgc3RyYXRlZ3k6IHt9XG4gICAgfSxcblxufTtcblxuRi51dGlsLnF1ZXJ5ID0gcmVxdWlyZSgnLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbkYudXRpbC5tYWtlU2VxdWVuY2UgPSByZXF1aXJlKCcuL3V0aWwvbWFrZS1zZXF1ZW5jZScpO1xuRi51dGlsLnJ1biA9IHJlcXVpcmUoJy4vdXRpbC9ydW4tdXRpbCcpO1xuRi51dGlsLmNsYXNzRnJvbSA9IHJlcXVpcmUoJy4vdXRpbC9pbmhlcml0Jyk7XG5cbkYuZmFjdG9yeS5UcmFuc3BvcnQgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5GLnRyYW5zcG9ydC5BamF4ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvYWpheC1odHRwLXRyYW5zcG9ydCcpO1xuXG5GLnNlcnZpY2UuVVJMID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xuRi5zZXJ2aWNlLkNvbmZpZyA9IHJlcXVpcmUoJy4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbkYuc2VydmljZS5SdW4gPSByZXF1aXJlKCcuL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRmlsZSA9IHJlcXVpcmUoJy4vc2VydmljZS9hZG1pbi1maWxlLXNlcnZpY2UnKTtcbkYuc2VydmljZS5WYXJpYWJsZXMgPSByZXF1aXJlKCcuL3NlcnZpY2UvdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRGF0YSA9IHJlcXVpcmUoJy4vc2VydmljZS9kYXRhLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuQXV0aCA9IHJlcXVpcmUoJy4vc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuV29ybGQgPSByZXF1aXJlKCcuL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5TdGF0ZSA9IHJlcXVpcmUoJy4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLlVzZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLk1lbWJlciA9IHJlcXVpcmUoJy4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Bc3NldCA9IHJlcXVpcmUoJy4vc2VydmljZS9hc3NldC1hcGktYWRhcHRlcicpO1xuXG5GLnN0b3JlLkNvb2tpZSA9IHJlcXVpcmUoJy4vc3RvcmUvY29va2llLXN0b3JlJyk7XG5GLmZhY3RvcnkuU3RvcmUgPSByZXF1aXJlKCcuL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcblxuRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvc2NlbmFyaW8tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLlJ1bk1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2F1dGgtbWFuYWdlcicpO1xuRi5tYW5hZ2VyLldvcmxkTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvd29ybGQtbWFuYWdlcicpO1xuXG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ2Fsd2F5cy1uZXcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvYWx3YXlzLW5ldy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5Wydjb25kaXRpb25hbC1jcmVhdGlvbiddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5LmlkZW50aXR5ID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9pZGVudGl0eS1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtcGVyc2lzdGVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLWluaXRpYWxpemVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpO1xuXG5GLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXInKTtcbkYuc2VydmljZS5DaGFubmVsID0gcmVxdWlyZSgnLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xuXG5GLnZlcnNpb24gPSAnPCU9IHZlcnNpb24gJT4nO1xuRi5hcGkgPSByZXF1aXJlKCcuL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuZ2xvYmFsLkYgPSBGO1xubW9kdWxlLmV4cG9ydHMgPSBGO1xuIiwiLyoqXG4qICMjIEF1dGhvcml6YXRpb24gTWFuYWdlclxuKlxuKiBUaGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIG1hbmFnZSB1c2VyIGF1dGhlbnRpY2F0aW9uIChsb2dnaW5nIGluIGFuZCBvdXQpIGFuZCBhdXRob3JpemF0aW9uIChrZWVwaW5nIHRyYWNrIG9mIHRva2Vucywgc2Vzc2lvbnMsIGFuZCBncm91cHMpIGZvciBwcm9qZWN0cy5cbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBpcyBtb3N0IHVzZWZ1bCBmb3IgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSB3aXRoIGFuIGFjY2VzcyBsZXZlbCBvZiBbQXV0aGVudGljYXRlZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2FjY2VzcykuIFRoZXNlIHByb2plY3RzIGFyZSBhY2Nlc3NlZCBieSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiBvbmUgb3IgbW9yZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS5cbipcbiogIyMjI1VzaW5nIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXJcbipcbiogVG8gdXNlIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZDpcbipcbiogICAgICAgdmFyIGF1dGhNZ3IgPSBuZXcgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKHtcbiogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgIHVzZXJOYW1lOiAnZW5kdXNlcjEnLFxuKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiogICAgICAgfSk7XG4qICAgICAgIGF1dGhNZ3IubG9naW4oKS50aGVuKGZ1bmN0aW9uICgpIHtcbiogICAgICAgICAgIGF1dGhNZ3IuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuKiAgICAgICB9KTtcbipcbipcbiogVGhlIGBvcHRpb25zYCBvYmplY3QgcGFzc2VkIHRvIHRoZSBgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKClgIGNhbGwgY2FuIGluY2x1ZGU6XG4qXG4qICAgKiBgYWNjb3VudGA6IFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICogYHVzZXJOYW1lYDogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLlxuKiAgICogYHBhc3N3b3JkYDogUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLlxuKiAgICogYHByb2plY3RgOiBUaGUgKipQcm9qZWN0IElEKiogZm9yIHRoZSBwcm9qZWN0IHRvIGxvZyB0aGlzIHVzZXIgaW50by4gT3B0aW9uYWwuXG4qICAgKiBgZ3JvdXBJZGA6IElkIG9mIHRoZSBncm91cCB0byB3aGljaCBgdXNlck5hbWVgIGJlbG9uZ3MuIFJlcXVpcmVkIGZvciBlbmQgdXNlcnMgaWYgdGhlIGBwcm9qZWN0YCBpcyBzcGVjaWZpZWQuXG4qXG4qIElmIHlvdSBwcmVmZXIgc3RhcnRpbmcgZnJvbSBhIHRlbXBsYXRlLCB0aGUgRXBpY2VudGVyIEpTIExpYnMgW0xvZ2luIENvbXBvbmVudF0oLi4vLi4vI2NvbXBvbmVudHMpIHVzZXMgdGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBhcyB3ZWxsLiBUaGlzIHNhbXBsZSBIVE1MIHBhZ2UgKGFuZCBhc3NvY2lhdGVkIENTUyBhbmQgSlMgZmlsZXMpIHByb3ZpZGVzIGEgbG9naW4gZm9ybSBmb3IgdGVhbSBtZW1iZXJzIGFuZCBlbmQgdXNlcnMgb2YgeW91ciBwcm9qZWN0LiBJdCBhbHNvIGluY2x1ZGVzIGEgZ3JvdXAgc2VsZWN0b3IgZm9yIGVuZCB1c2VycyB0aGF0IGFyZSBtZW1iZXJzIG9mIG11bHRpcGxlIGdyb3Vwcy5cbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBBdXRoQWRhcHRlciA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xudmFyIE1lbWJlckFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlcicpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIEJ1ZmZlciA9IHJlcXVpcmUoJ2J1ZmZlcicpLkJ1ZmZlcjtcbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4va2V5LW5hbWVzJyk7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBXaGVyZSB0byBzdG9yZSB1c2VyIGFjY2VzcyB0b2tlbnMgZm9yIHRlbXBvcmFyeSBhY2Nlc3MuIERlZmF1bHRzIHRvIHN0b3JpbmcgaW4gYSBjb29raWUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBzdG9yZTogeyBzeW5jaHJvbm91czogdHJ1ZSB9XG59O1xuXG52YXIgRVBJX0NPT0tJRV9LRVkgPSBrZXlOYW1lcy5FUElfQ09PS0lFX0tFWTtcbnZhciBFUElfU0VTU0lPTl9LRVkgPSBrZXlOYW1lcy5FUElfU0VTU0lPTl9LRVk7XG52YXIgc3RvcmU7XG52YXIgdG9rZW47XG52YXIgc2Vzc2lvbjtcblxuZnVuY3Rpb24gc2F2ZVNlc3Npb24odXNlckluZm8sIHN0b3JlKSB7XG4gICAgdmFyIHNlcmlhbGl6ZWQgPSBKU09OLnN0cmluZ2lmeSh1c2VySW5mbyk7XG4gICAgc3RvcmUuc2V0KEVQSV9TRVNTSU9OX0tFWSwgc2VyaWFsaXplZCk7XG5cbiAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgLy9qc2NzOmRpc2FibGVcbiAgICBzdG9yZS5zZXQoRVBJX0NPT0tJRV9LRVksIHVzZXJJbmZvLmF1dGhfdG9rZW4pO1xufVxuXG5mdW5jdGlvbiBnZXRTZXNzaW9uKHN0b3JlKSB7XG4gICAgdmFyIHNlc3Npb24gPSBzdG9yZS5nZXQoRVBJX1NFU1NJT05fS0VZKSB8fCAne30nO1xuICAgIHJldHVybiBKU09OLnBhcnNlKHNlc3Npb24pO1xufVxuXG5mdW5jdGlvbiBBdXRoTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZSh0aGlzLm9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB0aGlzLm9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICAvLyBudWxsIG1pZ2h0IHNwZWNpZmllZCB0byBkaXNhYmxlIHByb2plY3QgZmlsdGVyaW5nXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wcm9qZWN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdGhpcy5zdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh0aGlzLm9wdGlvbnMuc3RvcmUpO1xuICAgIHNlc3Npb24gPSBnZXRTZXNzaW9uKHRoaXMuc3RvcmUpO1xuICAgIHRva2VuID0gdGhpcy5zdG9yZS5nZXQoRVBJX0NPT0tJRV9LRVkpIHx8ICcnO1xuICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAvL2pzY3M6ZGlzYWJsZVxuICAgIHRoaXMuYXV0aEFkYXB0ZXIgPSBuZXcgQXV0aEFkYXB0ZXIodGhpcy5vcHRpb25zLCB7IHRva2VuOiBzZXNzaW9uLmF1dGhfdG9rZW4gfSk7XG59XG5cbnZhciBfZmluZFVzZXJJbkdyb3VwID0gZnVuY3Rpb24gKG1lbWJlcnMsIGlkKSB7XG4gICAgZm9yICh2YXIgaiA9IDA7IGo8bWVtYmVycy5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAobWVtYmVyc1tqXS51c2VySWQgPT09IGlkKSB7XG4gICAgICAgICAgICByZXR1cm4gbWVtYmVyc1tqXTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgcmV0dXJuIG51bGw7XG59O1xuXG5BdXRoTWFuYWdlci5wcm90b3R5cGUgPSAkLmV4dGVuZChBdXRoTWFuYWdlci5wcm90b3R5cGUsIHtcblxuICAgIC8qKlxuICAgICogTG9ncyB1c2VyIGluLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dpbih7XG4gICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgKiAgICAgICAgICAgdXNlck5hbWU6ICdlbmR1c2VyMScsXG4gICAgKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiAgICAqICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gZXhhY3RseSBvbmUgZ3JvdXBcbiAgICAqICAgICAgICAgICAgICAgLy8gKG9yIGlmIHRoZSBsb2dpbigpIGNhbGwgaXMgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGUgZ3JvdXAgaWQpXG4gICAgKiAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIGhlcmVcbiAgICAqICAgICAgICAgICB9KVxuICAgICogICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIG11bHRpcGxlIGdyb3VwcyxcbiAgICAqICAgICAgICAgICAgICAgLy8gdGhlIGxvZ2luKCkgY2FsbCBmYWlsc1xuICAgICogICAgICAgICAgICAgICAvLyBhbmQgcmV0dXJucyBhbGwgZ3JvdXBzIG9mIHdoaWNoIHRoZSB1c2VyIGlzIGEgbWVtYmVyXG4gICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IHN0YXR1c09iai51c2VyR3JvdXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5uYW1lLCBzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5ncm91cElkKTtcbiAgICAqICAgICAgICAgICAgICAgfVxuICAgICogICAgICAgICAgIH0pO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLiBJZiBub3QgcGFzc2VkIGluIHdoZW4gY3JlYXRpbmcgYW4gaW5zdGFuY2Ugb2YgdGhlIG1hbmFnZXIgKGBGLm1hbmFnZXIuQXV0aE1hbmFnZXIoKWApLCB0aGVzZSBvcHRpb25zIHNob3VsZCBpbmNsdWRlOlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmFjY291bnRgIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnVzZXJOYW1lYCBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMucGFzc3dvcmRgIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5wcm9qZWN0YCAoT3B0aW9uYWwpIFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhlIHByb2plY3QgdG8gbG9nIHRoaXMgdXNlciBpbnRvLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpZiB0aGUgYHByb2plY3RgIGlzIHNwZWNpZmllZCBhbmQgaWYgdGhlIGVuZCB1c2VycyBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3RoZXJ3aXNlIG9wdGlvbmFsLlxuICAgICovXG4gICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AsIGVycm9yOiAkLm5vb3AgfSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuICAgICAgICB2YXIgb3V0RXJyb3IgPSBhZGFwdGVyT3B0aW9ucy5lcnJvcjtcbiAgICAgICAgdmFyIGdyb3VwSWQgPSBhZGFwdGVyT3B0aW9ucy5ncm91cElkO1xuXG4gICAgICAgIHZhciBhY2NvdW50TmFtZSA9IChvcHRpb25zICYmIG9wdGlvbnMuYWNjb3VudCkgPyBvcHRpb25zLmFjY291bnQgOiB0aGlzLm9wdGlvbnMuYWNjb3VudDtcbiAgICAgICAgdmFyIHByb2plY3ROYW1lID0gKG9wdGlvbnMgJiYgb3B0aW9ucy5wcm9qZWN0KSA/IG9wdGlvbnMucHJvamVjdCA6IHRoaXMub3B0aW9ucy5wcm9qZWN0O1xuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuc3RvcmUucm9vdCA9PT0gdW5kZWZpbmVkICYmIGFjY291bnROYW1lICYmIHByb2plY3ROYW1lKSB7XG4gICAgICAgICAgICB0aGlzLnN0b3JlLnNlcnZpY2VPcHRpb25zLnJvb3QgPSAnL2FwcC8nICsgYWNjb3VudE5hbWUgKyAnLycgKyBwcm9qZWN0TmFtZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBkZWNvZGVUb2tlbiA9IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgICAgdmFyIGVuY29kZWQgPSB0b2tlbi5zcGxpdCgnLicpWzFdO1xuICAgICAgICAgICAgd2hpbGUgKGVuY29kZWQubGVuZ3RoICUgNCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIGVuY29kZWQgKz0gJz0nO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZGVjb2RlID0gd2luZG93LmF0b2IgPyB3aW5kb3cuYXRvYiA6IGZ1bmN0aW9uIChlbmNvZGVkKSB7IHJldHVybiBuZXcgQnVmZmVyKGVuY29kZWQsICdiYXNlNjQnKS50b1N0cmluZygnYXNjaWknKTsgfTtcblxuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGVjb2RlKGVuY29kZWQpKTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgaGFuZGxlR3JvdXBFcnJvciA9IGZ1bmN0aW9uIChtZXNzYWdlLCBzdGF0dXNDb2RlLCBkYXRhKSB7XG4gICAgICAgICAgICAvLyBsb2dvdXQgdGhlIHVzZXIgc2luY2UgaXQncyBpbiBhbiBpbnZhbGlkIHN0YXRlIHdpdGggbm8gZ3JvdXAgc2VsZWN0ZWRcbiAgICAgICAgICAgIF90aGlzLmxvZ291dCgpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBlcnJvciA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkYXRhLCB7IHN0YXR1c1RleHQ6IG1lc3NhZ2UsIHN0YXR1czogc3RhdHVzQ29kZSB9KTtcbiAgICAgICAgICAgICAgICAkZC5yZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZVN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAgICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgICAgICB0b2tlbiA9IHJlc3BvbnNlLmFjY2Vzc190b2tlbjtcbiAgICAgICAgICAgIHZhciB1c2VySW5mbyA9IGRlY29kZVRva2VuKHRva2VuKTtcbiAgICAgICAgICAgIHZhciB1c2VyR3JvdXBPcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIGFkYXB0ZXJPcHRpb25zLCB7IHN1Y2Nlc3M6ICQubm9vcCwgdG9rZW46IHRva2VuIH0pO1xuICAgICAgICAgICAgX3RoaXMuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogdXNlckluZm8udXNlcl9pZCwgdG9rZW46IHRva2VuIH0sIHVzZXJHcm91cE9wdHMpLmRvbmUoIGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGEgPSB7YXV0aDogcmVzcG9uc2UsIHVzZXI6IHVzZXJJbmZvLCB1c2VyR3JvdXBzOiBtZW1iZXJJbmZvLCBncm91cFNlbGVjdGlvbjoge30gfTtcblxuICAgICAgICAgICAgICAgIHZhciBzZXNzaW9uSW5mbyA9IHtcbiAgICAgICAgICAgICAgICAgICAgJ2F1dGhfdG9rZW4nOiB0b2tlbixcbiAgICAgICAgICAgICAgICAgICAgJ2FjY291bnQnOiBhZGFwdGVyT3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgICAgICAncHJvamVjdCc6IGFkYXB0ZXJPcHRpb25zLnByb2plY3QsXG4gICAgICAgICAgICAgICAgICAgICd1c2VySWQnOiB1c2VySW5mby51c2VyX2lkXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAvLyBUaGUgZ3JvdXAgaXMgbm90IHJlcXVpcmVkIGlmIHRoZSB1c2VyIGlzIG5vdCBsb2dnaW5nIGludG8gYSBwcm9qZWN0XG4gICAgICAgICAgICAgICAgaWYgKCFhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHNhdmVTZXNzaW9uKHNlc3Npb25JbmZvLCBfdGhpcy5zdG9yZSk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBncm91cCA9IG51bGw7XG4gICAgICAgICAgICAgICAgaWYgKG1lbWJlckluZm8ubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoZSB1c2VyIGhhcyBubyBncm91cHMgYXNzb2NpYXRlZCBpbiB0aGlzIGFjY291bnQnLCA0MDEsIGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZW1iZXJJbmZvLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTZWxlY3QgdGhlIG9ubHkgZ3JvdXBcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBtZW1iZXJJbmZvWzBdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobWVtYmVySW5mby5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChncm91cElkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmlsdGVyZWRHcm91cHMgPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKHJlc0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc0dyb3VwLmdyb3VwSWQgPT09IGdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gZmlsdGVyZWRHcm91cHMubGVuZ3RoID09PSAxID8gZmlsdGVyZWRHcm91cHNbMF0gOiBudWxsO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBncm91cFNlbGVjdGlvbiA9IGdyb3VwLmdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEuZ3JvdXBTZWxlY3Rpb25bYWRhcHRlck9wdGlvbnMucHJvamVjdF0gPSBncm91cFNlbGVjdGlvbjtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNlc3Npb25JbmZvV2l0aEdyb3VwID0gJC5leHRlbmQoe30sIHNlc3Npb25JbmZvLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAnZ3JvdXBJZCc6IGdyb3VwLmdyb3VwSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAnZ3JvdXBOYW1lJzogZ3JvdXAubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICdpc0ZhYyc6IF9maW5kVXNlckluR3JvdXAoZ3JvdXAubWVtYmVycywgdXNlckluZm8udXNlcl9pZCkucm9sZSA9PT0gJ2ZhY2lsaXRhdG9yJ1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgc2F2ZVNlc3Npb24oc2Vzc2lvbkluZm9XaXRoR3JvdXAsIF90aGlzLnN0b3JlKTtcbiAgICAgICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoaXMgdXNlciBpcyBhc3NvY2lhdGVkIHdpdGggbW9yZSB0aGFuIG9uZSBncm91cC4gUGxlYXNlIHNwZWNpZnkgYSBncm91cCBpZCB0byBsb2cgaW50byBhbmQgdHJ5IGFnYWluJywgNDAzLCBkYXRhKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGhhbmRsZVN1Y2Nlc3M7XG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vIFRyeSB0byBsb2dpbiBhcyBhIHN5c3RlbSB1c2VyXG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuYWNjb3VudCA9IG51bGw7XG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuZXJyb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdChyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIF90aGlzLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuYXV0aEFkYXB0ZXIubG9naW4oYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAqIExvZ3MgdXNlciBvdXQuXG4gICAgKlxuICAgICogKipFeGFtcGxlKipcbiAgICAqXG4gICAgKiAgICAgICBhdXRoTWdyLmxvZ291dCgpO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICovXG4gICAgbG9nb3V0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgYWRhcHRlck9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHRva2VuOiB0b2tlbiB9LCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciByZW1vdmVDb29raWVGbiA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgc3RvcmUucmVtb3ZlKEVQSV9DT09LSUVfS0VZLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICBzdG9yZS5yZW1vdmUoRVBJX1NFU1NJT05fS0VZLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICB0b2tlbiA9ICcnO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhBZGFwdGVyLmxvZ291dChhZGFwdGVyT3B0aW9ucykuZG9uZShyZW1vdmVDb29raWVGbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGV4aXN0aW5nIHVzZXIgYWNjZXNzIHRva2VuIGlmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluLiBPdGhlcndpc2UsIGxvZ3MgdGhlIHVzZXIgaW4sIGNyZWF0aW5nIGEgbmV3IHVzZXIgYWNjZXNzIHRva2VuLCBhbmQgcmV0dXJucyB0aGUgbmV3IHRva2VuLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBhdXRoTWdyLmdldFRva2VuKClcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coJ015IHRva2VuIGlzICcsIHRva2VuKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgaWYgKHRva2VuKSB7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKHRva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICogICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKylcbiAgICAgKiAgICAgICAgICAgICAgICAgIHsgY29uc29sZS5sb2coZ3JvdXBzW2ldLm5hbWUpOyB9XG4gICAgICogICAgICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIHBhcnRpY3VsYXIgdXNlclxuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHt1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB0b2tlbjogc2F2ZWRQcm9qQWNjZXNzVG9rZW4gfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcGFyYW1zYCBPYmplY3Qgd2l0aCBhIHVzZXJJZCBhbmQgdG9rZW4gcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSB1c2VySWQuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBPdGhlcndpc2UsIHBhc3MgYSBzdHJpbmcuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGBwYXJhbXMudG9rZW5gIFRoZSBhdXRob3JpemF0aW9uIGNyZWRlbnRpYWxzIChhY2Nlc3MgdG9rZW4pIHRvIHVzZSBmb3IgY2hlY2tpbmcgdGhlIGdyb3VwcyBmb3IgdGhpcyB1c2VyLiBJZiBsb29raW5nIHVwIGdyb3VwcyBmb3IgdGhlIGN1cnJlbnRseSBsb2dnZWQgaW4gdXNlciwgdGhpcyBpcyBpbiB0aGUgc2Vzc2lvbiBpbmZvcm1hdGlvbi4gQSB0ZWFtIG1lbWJlcidzIHRva2VuIG9yIGEgcHJvamVjdCBhY2Nlc3MgdG9rZW4gY2FuIGFjY2VzcyBhbGwgdGhlIGdyb3VwcyBmb3IgYWxsIGVuZCB1c2VycyBpbiB0aGUgdGVhbSBvciBwcm9qZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKi9cbiAgICBnZXRVc2VyR3JvdXBzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHsgc3VjY2VzczogJC5ub29wIH0sIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAobWVtYmVySW5mbykge1xuICAgICAgICAgICAgLy8gVGhlIG1lbWJlciBBUEkgaXMgYXQgdGhlIGFjY291bnQgc2NvcGUsIHdlIGZpbHRlciBieSBwcm9qZWN0XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICAgICAgICAgIG1lbWJlckluZm8gPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBncm91cC5wcm9qZWN0ID09PSBhZGFwdGVyT3B0aW9ucy5wcm9qZWN0O1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRTdWNjZXNzLmFwcGx5KHRoaXMsIFttZW1iZXJJbmZvXSk7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKG1lbWJlckluZm8pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBtZW1iZXJBZGFwdGVyID0gbmV3IE1lbWJlckFkYXB0ZXIoeyB0b2tlbjogcGFyYW1zLnRva2VuIH0pO1xuICAgICAgICBtZW1iZXJBZGFwdGVyLmdldEdyb3Vwc0ZvclVzZXIocGFyYW1zLCBhZGFwdGVyT3B0aW9ucykuZmFpbCgkZC5yZWplY3QpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHNlc3Npb24gaW5mb3JtYXRpb24gZm9yIHRoZSBjdXJyZW50IHVzZXIsIGluY2x1ZGluZyB0aGUgYHVzZXJJZGAsIGBhY2NvdW50YCwgYHByb2plY3RgLCBgZ3JvdXBJZGAsIGBncm91cE5hbWVgLCBgaXNGYWNgICh3aGV0aGVyIHRoZSBlbmQgdXNlciBpcyBhIGZhY2lsaXRhdG9yIG9mIHRoaXMgZ3JvdXApLCBhbmQgYGF1dGhfdG9rZW5gICh1c2VyIGFjY2VzcyB0b2tlbikuXG4gICAgICpcbiAgICAgKiAqSW1wb3J0YW50KjogVGhpcyBtZXRob2QgaXMgc3luY2hyb25vdXMuIFRoZSBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHJldHVybmVkIGltbWVkaWF0ZWx5IGluIGFuIG9iamVjdDsgbm8gY2FsbGJhY2tzIG9yIHByb21pc2VzIGFyZSBuZWVkZWQuXG4gICAgICpcbiAgICAgKiBCeSBkZWZhdWx0LCBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHN0b3JlZCBpbiBhIGNvb2tpZSBpbiB0aGUgYnJvd3Nlci4gWW91IGNhbiBjaGFuZ2UgdGhpcyB3aXRoIHRoZSBgc3RvcmVgIGNvbmZpZ3VyYXRpb24gb3B0aW9uLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm86IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiBnZXRTZXNzaW9uKHRoaXMuc3RvcmUsIG9wdGlvbnMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEF1dGhNYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2hhbm5lbCA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlJyk7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgYXJvdW5kIHRoZSBkZWZhdWx0IFtjb21ldGQgSmF2YVNjcmlwdCBsaWJyYXJ5XShodHRwOi8vZG9jcy5jb21ldGQub3JnLzIvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCksIGAkLmNvbWV0ZGAuIEl0IHByb3ZpZGVzIGEgZmV3IG5pY2UgZmVhdHVyZXMgdGhhdCBgJC5jb21ldGRgIGRvZXNuJ3QsIGluY2x1ZGluZzpcbiAqXG4gKiAqIEF1dG9tYXRpYyByZS1zdWJzY3JpcHRpb24gdG8gY2hhbm5lbHMgaWYgeW91IGxvc2UgeW91ciBjb25uZWN0aW9uXG4gKiAqIE9ubGluZSAvIE9mZmxpbmUgbm90aWZpY2F0aW9uc1xuICogKiAnRXZlbnRzJyBmb3IgY29tZXRkIG5vdGlmaWNhdGlvbnMgKGluc3RlYWQgb2YgaGF2aW5nIHRvIGxpc3RlbiBvbiBzcGVjaWZpYyBtZXRhIGNoYW5uZWxzKVxuICpcbiAqIFdoaWxlIHlvdSBjYW4gd29yayBkaXJlY3RseSB3aXRoIHRoZSBDaGFubmVsIE1hbmFnZXIgdGhyb3VnaCBOb2RlLmpzIChmb3IgZXhhbXBsZSwgYHJlcXVpcmUoJ21hbmFnZXIvY2hhbm5lbC1tYW5hZ2VyJylgKSAtLSBvciBldmVuIHdvcmsgZGlyZWN0bHkgd2l0aCBgJC5jb21ldGRgIGFuZCBFcGljZW50ZXIncyB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIC0tIG1vc3Qgb2Z0ZW4gaXQgd2lsbCBiZSBlYXNpZXN0IHRvIHdvcmsgd2l0aCB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKS4gVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIHRoYXQgaW5zdGFudGlhdGVzIGEgQ2hhbm5lbCBNYW5hZ2VyIHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgTWFuYWdlci4gKFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLilcbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgTWFuYWdlciBpbiBjbGllbnQtc2lkZSBKYXZhU2NyaXB0LCBpbnN0YW50aWF0ZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSwgZ2V0IHRoZSBjaGFubmVsLCB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gKlxuICogICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAqICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgTWFuYWdlci4gQmVzaWRlcyB0aGUgY29tbW9uIG9wdGlvbnMgbGlzdGVkIGhlcmUsIHNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIG90aGVyIHN1cHBvcnRlZCBvcHRpb25zLlxuICogKiBgb3B0aW9ucy51cmxgIFRoZSBDb21ldGQgZW5kcG9pbnQgVVJMLlxuICogKiBgb3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkYCBXaGV0aGVyIHdlYnNvY2tldCBzdXBwb3J0IGlzIGFjdGl2ZSAoYm9vbGVhbikuXG4gKiAqIGBvcHRpb25zLmNoYW5uZWxgIE90aGVyIGRlZmF1bHRzIHRvIHBhc3Mgb24gdG8gaW5zdGFuY2VzIG9mIHRoZSB1bmRlcmx5aW5nIENoYW5uZWwgU2VydmljZS4gU2VlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pIGZvciBkZXRhaWxzLlxuICpcbiAqL1xudmFyIENoYW5uZWxNYW5hZ2VyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICBpZiAoISQuY29tZXRkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tZXRkIGxpYnJhcnkgbm90IGZvdW5kLiBQbGVhc2UgaW5jbHVkZSBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy51cmwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhbiB1cmwgZm9yIHRoZSBjb21ldGQgc2VydmVyJyk7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbG9nIGxldmVsIGZvciB0aGUgY2hhbm5lbCAobG9ncyB0byBjb25zb2xlKS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGxvZ0xldmVsOiAnaW5mbycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlLiBEZWZhdWx0cyB0byBgZmFsc2VgOyBFcGljZW50ZXIgZG9lc24ndCBjdXJyZW50bHkgc3VwcG9ydCBjb21tdW5pY2F0aW9uIHRocm91Z2ggd2Vic29ja2V0cy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICB3ZWJzb2NrZXRFbmFibGVkOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogSWYgZmFsc2UgZWFjaCBpbnN0YW5jZSBvZiBDaGFubmVsIHdpbGwgaGF2ZSBhIHNlcGFyYXRlIGNvbWV0ZCBjb25uZWN0aW9uIHRvIHNlcnZlciwgd2hpY2ggY291bGQgYmUgbm9pc3kuIFNldCB0byB0cnVlIHRvIHJlLXVzZSB0aGUgc2FtZSBjb25uZWN0aW9uIGFjcm9zcyBpbnN0YW5jZXMuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2hhcmVDb25uZWN0aW9uOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLyksIHdoaWNoIGFyZSBjcmVhdGVkIHRocm91Z2ggYGdldENoYW5uZWwoKWAuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBjaGFubmVsOiB7XG5cbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMgPSBbXTtcbiAgICB0aGlzLm9wdGlvbnMgPSBkZWZhdWx0Q29tZXRPcHRpb25zO1xuXG4gICAgaWYgKGRlZmF1bHRDb21ldE9wdGlvbnMuc2hhcmVDb25uZWN0aW9uICYmIENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkKSB7XG4gICAgICAgIHRoaXMuY29tZXRkID0gQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQ7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICB2YXIgY29tZXRkID0gbmV3ICQuQ29tZXRkKCk7XG4gICAgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQgPSBjb21ldGQ7XG5cbiAgICBjb21ldGQud2Vic29ja2V0RW5hYmxlZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMud2Vic29ja2V0RW5hYmxlZDtcblxuICAgIHRoaXMuaXNDb25uZWN0ZWQgPSBmYWxzZTtcbiAgICB2YXIgY29ubmVjdGlvbkJyb2tlbiA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignZGlzY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIGNvbm5lY3Rpb25TdWNjZWVkZWQgPSBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIoJ2Nvbm5lY3QnLCBtZXNzYWdlKTtcbiAgICB9O1xuICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICBjb21ldGQuY29uZmlndXJlKGRlZmF1bHRDb21ldE9wdGlvbnMpO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9jb25uZWN0JywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgdmFyIHdhc0Nvbm5lY3RlZCA9IHRoaXMuaXNDb25uZWN0ZWQ7XG4gICAgICAgIHRoaXMuaXNDb25uZWN0ZWQgPSAobWVzc2FnZS5zdWNjZXNzZnVsID09PSB0cnVlKTtcbiAgICAgICAgaWYgKCF3YXNDb25uZWN0ZWQgJiYgdGhpcy5pc0Nvbm5lY3RlZCkgeyAvL0Nvbm5lY3RpbmcgZm9yIHRoZSBmaXJzdCB0aW1lXG4gICAgICAgICAgICBjb25uZWN0aW9uU3VjY2VlZGVkLmNhbGwodGhpcywgbWVzc2FnZSk7XG4gICAgICAgIH0gZWxzZSBpZiAod2FzQ29ubmVjdGVkICYmICF0aGlzLmlzQ29ubmVjdGVkKSB7IC8vT25seSB0aHJvdyBkaXNjb25uZWN0ZWQgbWVzc2FnZSBmcm8gdGhlIGZpcnN0IGRpc2Nvbm5lY3QsIG5vdCBvbmNlIHBlciB0cnlcbiAgICAgICAgICAgIGNvbm5lY3Rpb25Ccm9rZW4uY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH0uYmluZCh0aGlzKSk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Rpc2Nvbm5lY3QnLCBjb25uZWN0aW9uQnJva2VuKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvaGFuZHNoYWtlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgaWYgKG1lc3NhZ2Uuc3VjY2Vzc2Z1bCkge1xuICAgICAgICAgICAgLy9odHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0X3N1YnNjcmliZS5odG1sI2phdmFzY3JpcHRfc3Vic2NyaWJlX21ldGFfY2hhbm5lbHNcbiAgICAgICAgICAgIC8vIF4gXCJkeW5hbWljIHN1YnNjcmlwdGlvbnMgYXJlIGNsZWFyZWQgKGxpa2UgYW55IG90aGVyIHN1YnNjcmlwdGlvbikgYW5kIHRoZSBhcHBsaWNhdGlvbiBuZWVkcyB0byBmaWd1cmUgb3V0IHdoaWNoIGR5bmFtaWMgc3Vic2NyaXB0aW9uIG11c3QgYmUgcGVyZm9ybWVkIGFnYWluXCJcbiAgICAgICAgICAgIGNvbWV0ZC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgJChtZS5jdXJyZW50U3Vic2NyaXB0aW9ucykuZWFjaChmdW5jdGlvbiAoaW5kZXgsIHN1YnMpIHtcbiAgICAgICAgICAgICAgICAgICAgY29tZXRkLnJlc3Vic2NyaWJlKHN1YnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vT3RoZXIgaW50ZXJlc3RpbmcgZXZlbnRzIGZvciByZWZlcmVuY2VcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3N1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3N1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWJzY3JpYmUnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCd1bnN1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvcHVibGlzaCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3B1Ymxpc2gnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3Vuc3VjY2Vzc2Z1bCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ2Vycm9yJywgbWVzc2FnZSk7XG4gICAgfSk7XG5cbiAgICBjb21ldGQuaGFuZHNoYWtlKCk7XG5cbiAgICB0aGlzLmNvbWV0ZCA9IGNvbWV0ZDtcbn07XG5cblxuQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgIHZhciBjaGFubmVsID0gY20uZ2V0Q2hhbm5lbCgpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvL0lmIHlvdSBqdXN0IHdhbnQgdG8gcGFzcyBpbiBhIHN0cmluZ1xuICAgICAgICBpZiAob3B0aW9ucyAmJiAhJC5pc1BsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAgICAgdHJhbnNwb3J0OiB0aGlzLmNvbWV0ZFxuICAgICAgICB9O1xuICAgICAgICB2YXIgY2hhbm5lbCA9IG5ldyBDaGFubmVsKCQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLm9wdGlvbnMuY2hhbm5lbCwgZGVmYXVsdHMsIG9wdGlvbnMpKTtcblxuXG4gICAgICAgIC8vV3JhcCBzdWJzIGFuZCB1bnN1YnMgc28gd2UgY2FuIHVzZSBpdCB0byByZS1hdHRhY2ggaGFuZGxlcnMgYWZ0ZXIgYmVpbmcgZGlzY29ubmVjdGVkXG4gICAgICAgIHZhciBzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHN1YmlkID0gc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyAgPSB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmNvbmNhdChzdWJpZCk7XG4gICAgICAgICAgICByZXR1cm4gc3ViaWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuXG4gICAgICAgIHZhciB1bnN1YnMgPSBjaGFubmVsLnVuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnVuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJlbW92ZWQgPSB1bnN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zW2ldLmlkID09PSByZW1vdmVkLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZW1vdmVkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlclxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIChtb3JlIGdlbmVyaWMpIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pLCB0byBpbnN0YW50aWF0ZSBpdCB3aXRoIEVwaWNlbnRlci1zcGVjaWZpYyBkZWZhdWx0cy4gSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGluY2x1ZGluZyBhIG5vdGlmaWNhdGlvbiBvciBjaGF0IGZlYXR1cmUgaW4geW91ciBwcm9qZWN0LCB1c2luZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIHByb2JhYmx5IHRoZSBlYXNpZXN0IHdheSB0byBnZXQgc3RhcnRlZC5cbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXI6IGluc3RhbnRpYXRlIGl0LCBnZXQgdGhlIGNoYW5uZWwgb2YgdGhlIHNjb3BlIHlvdSB3YW50IChbdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLCBvciBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpKSwgdGhlbiB1c2UgdGhlIGNoYW5uZWwncyBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIHN1YnNjcmliZSB0byB0b3BpY3Mgb3IgcHVibGlzaCBkYXRhIHRvIHRvcGljcy5cbiAqXG4gKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAqXG4gKiBGb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIEVwaWNlbnRlcidzIHB1c2ggY2hhbm5lbCwgc2VlIHRoZSBpbnRyb2R1Y3Rvcnkgbm90ZXMgb24gdGhlIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIHBhZ2UuXG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYHNlcnZlcmAgT2JqZWN0IHdpdGggZGV0YWlscyBhYm91dCB0aGUgRXBpY2VudGVyIHByb2plY3QgZm9yIHRoaXMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbnN0YW5jZS5cbiAqICogYHNlcnZlci5hY2NvdW50YCBUaGUgRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgc2VydmVyLnByb2plY3RgIEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICovXG5cbnZhciBDaGFubmVsTWFuYWdlciA9IHJlcXVpcmUoJy4vY2hhbm5lbC1tYW5hZ2VyJyk7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgdXJsU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlJyk7XG5cbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBzZXNzaW9uID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG52YXIgZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvciA9IGZ1bmN0aW9uICh2YWx1ZSwgc2Vzc2lvbktleU5hbWUsIHNldHRpbmdzKSB7XG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgaWYgKHNldHRpbmdzICYmIHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXSkge1xuICAgICAgICAgICAgdmFsdWUgPSBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV07XG4gICAgICAgIH0gZWxzZSBpZiAodXNlckluZm9bc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHVzZXJJbmZvW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihzZXNzaW9uS2V5TmFtZSArICcgbm90IGZvdW5kLiBQbGVhc2UgbG9nLWluIGFnYWluLCBvciBzcGVjaWZ5ICcgKyBzZXNzaW9uS2V5TmFtZSArICcgZXhwbGljaXRseScpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbn07XG52YXIgX19zdXBlciA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZTtcbnZhciBFcGljZW50ZXJDaGFubmVsTWFuYWdlciA9IGNsYXNzRnJvbShDaGFubmVsTWFuYWdlciwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcblxuICAgICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgICAgICBhY2NvdW50OiB1c2VySW5mby5hY2NvdW50LFxuICAgICAgICAgICAgcHJvamVjdDogdXNlckluZm8ucHJvamVjdCxcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIHVzZXJJbmZvLCBvcHRpb25zKTtcblxuICAgICAgICB2YXIgdXJsT3B0cyA9IHVybFNlcnZpY2UoZGVmYXVsdENvbWV0T3B0aW9ucy5zZXJ2ZXIpO1xuICAgICAgICBpZiAoIWRlZmF1bHRDb21ldE9wdGlvbnMudXJsKSB7XG4gICAgICAgICAgICAvL0RlZmF1bHQgZXBpY2VudGVyIGNvbWV0ZCBlbmRwb2ludFxuICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy51cmwgPSB1cmxPcHRzLnByb3RvY29sICsgJzovLycgKyB1cmxPcHRzLmhvc3QgKyAnL2NoYW5uZWwvc3Vic2NyaWJlJztcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgZGVmYXVsdENvbWV0T3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBnaXZlbiBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLiBUaGUgZ3JvdXAgbXVzdCBleGlzdCBpbiB0aGUgYWNjb3VudCAodGVhbSkgYW5kIHByb2plY3QgcHJvdmlkZWQuXG4gICAgICpcbiAgICAgKiBUaGVyZSBhcmUgbm8gbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWw7IGFsbCBtZXNzYWdlcyBhcmUgdXNlci1vcmlnaW5hdGVkLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJ2Jyb2FkY2FzdHMnLCBjYWxsYmFjayk7XG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBHcm91cCB0byBicm9hZGNhc3QgdG8uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldEdyb3VwQ2hhbm5lbDogZnVuY3Rpb24gKGdyb3VwTmFtZSkge1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScpO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2dyb3VwJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lXS5qb2luKCcvJyk7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICogICAgICAgICBydW46IHsgbW9kZWw6ICdtb2RlbC5lcW4nIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICogICAgIHdvcmxkTWFuYWdlci5nZXRDdXJyZW50V29ybGQoKS50aGVuKGZ1bmN0aW9uICh3b3JsZE9iamVjdCwgd29ybGRBZGFwdGVyKSB7XG4gICAgICogICAgICAgICB2YXIgd29ybGRDaGFubmVsID0gY20uZ2V0V29ybGRDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHdvcmxkQ2hhbm5lbC5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICogICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICogICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFRoZSB3b3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFdvcmxkQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCBncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHdvcmxkaWQgPSAoJC5pc1BsYWluT2JqZWN0KHdvcmxkKSAmJiB3b3JsZC5pZCkgPyB3b3JsZC5pZCA6IHdvcmxkO1xuICAgICAgICBpZiAoIXdvcmxkaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgYSB3b3JsZCBpZCcpO1xuICAgICAgICB9XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJyk7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvd29ybGQnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgY3VycmVudCBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaW4gdGhhdCB1c2VyJ3MgY3VycmVudCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS4gTm90ZSB0aGF0IHRoaXMgY2hhbm5lbCBvbmx5IGdldHMgbm90aWZpY2F0aW9ucyBmb3Igd29ybGRzIGN1cnJlbnRseSBpbiBtZW1vcnkuIChTZWUgbW9yZSBiYWNrZ3JvdW5kIG9uIFtwZXJzaXN0ZW5jZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlKS4pXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB1c2VyQ2hhbm5lbCA9IGNtLmdldFVzZXJDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHVzZXJDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFVzZXJDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXIsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVzZXJpZCA9ICgkLmlzUGxhaW5PYmplY3QodXNlcikgJiYgdXNlci5pZCkgPyB1c2VyLmlkIDogdXNlcjtcbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkLCB1c2VyaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIHRoYXQgYXV0b21hdGljYWxseSB0cmFja3MgdGhlIHByZXNlbmNlIG9mIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhhdCBpcywgd2hldGhlciB0aGUgZW5kIHVzZXIgaXMgY3VycmVudGx5IG9ubGluZSBpbiB0aGlzIGdyb3VwIGFuZCB3b3JsZC4gTm90aWZpY2F0aW9ucyBhcmUgYXV0b21hdGljYWxseSBzZW50IHdoZW4gdGhlIGVuZCB1c2VyIGNvbWVzIG9ubGluZSwgYW5kIHdoZW4gdGhlIGVuZCB1c2VyIGdvZXMgb2ZmbGluZSAobm90IHByZXNlbnQgZm9yIG1vcmUgdGhhbiAyIG1pbnV0ZXMpLiBVc2VmdWwgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZm9yIGxldHRpbmcgZWFjaCBlbmQgdXNlciBrbm93IHdoZXRoZXIgb3RoZXIgdXNlcnMgaW4gdGhlaXIgc2hhcmVkIHdvcmxkIGFyZSBhbHNvIG9ubGluZS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIG1vZGVsOiAnbW9kZWwuZXFuJ1xuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZFNlcnZpY2UpIHtcbiAgICAgKiAgICAgICAgIHZhciBwcmVzZW5jZUNoYW5uZWwgPSBjbS5nZXRQcmVzZW5jZUNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgcHJlc2VuY2VDaGFubmVsLm9uKCdwcmVzZW5jZScsIGZ1bmN0aW9uIChldnQsIG5vdGlmaWNhdGlvbikge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZyhub3RpZmljYXRpb24ub25saW5lLCBub3RpZmljYXRpb24udXNlcklkKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB3b3JsZGAgV29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB1c2VyaWRgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFByZXNlbmNlQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCB1c2VyaWQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgdmFyIGxhc3RQaW5nVGltZSA9IHsgfTtcblxuICAgICAgICB2YXIgUElOR19JTlRFUlZBTCA9IDYwMDA7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCdpbnRlcm5hbC1waW5nLWNoYW5uZWwnLCBmdW5jdGlvbiAobm90aWZpY2F0aW9uKSB7XG4gICAgICAgICAgICB2YXIgaW5jb21pbmdVc2VySWQgPSBub3RpZmljYXRpb24uZGF0YS51c2VyO1xuICAgICAgICAgICAgaWYgKCFsYXN0UGluZ1RpbWVbaW5jb21pbmdVc2VySWRdICYmIGluY29taW5nVXNlcklkICE9PSB1c2VyaWQpIHtcbiAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDogaW5jb21pbmdVc2VySWQsIG9ubGluZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIHsgdXNlcjogdXNlcmlkIH0pO1xuXG4gICAgICAgICAgICAkLmVhY2gobGFzdFBpbmdUaW1lLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBub3cgPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSAmJiB2YWx1ZSArIChQSU5HX0lOVEVSVkFMICogMikgPCBub3cpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2tleV0gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDoga2V5LCBvbmxpbmU6IGZhbHNlIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBQSU5HX0lOVEVSVkFMKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIGNvbGxlY3Rpb24uIChUaGUgY29sbGVjdGlvbiBuYW1lIGlzIHNwZWNpZmllZCBpbiB0aGUgYHJvb3RgIGFyZ3VtZW50IHdoZW4gdGhlIFtEYXRhIFNlcnZpY2VdKC4uL2RhdGEtYXBpLXNlcnZpY2UvKSBpcyBpbnN0YW50aWF0ZWQuKSBNdXN0IGJlIG9uZSBvZiB0aGUgY29sbGVjdGlvbnMgaW4gdGhpcyBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBhdXRvbWF0aWMgbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWwgd2hlbiBkYXRhIGlzIGNyZWF0ZWQsIHVwZGF0ZWQsIG9yIGRlbGV0ZWQgaW4gdGhpcyBjb2xsZWN0aW9uLiBTZWUgbW9yZSBvbiBbYXV0b21hdGljIG1lc3NhZ2VzIHRvIHRoZSBkYXRhIGNoYW5uZWxdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNkYXRhLW1lc3NhZ2VzKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZ2MgPSBjbS5nZXREYXRhQ2hhbm5lbCgnc3VydmV5LXJlc3BvbnNlcycpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEsIG1ldGEpIHtcbiAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIG1ldGEuZGF0ZSBpcyB0aW1lIG9mIGNoYW5nZSxcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnN1YlR5cGUgaXMgdGhlIGtpbmQgb2YgY2hhbmdlOiBuZXcsIHVwZGF0ZSwgb3IgZGVsZXRlXG4gICAgICogICAgICAgICAgLy8gbWV0YS5wYXRoIGlzIHRoZSBmdWxsIHBhdGggdG8gdGhlIGNoYW5nZWQgZGF0YVxuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKG1ldGEpO1xuICAgICAqICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgY29sbGVjdGlvbmAgTmFtZSBvZiBjb2xsZWN0aW9uIHdob3NlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIHlvdSB3YW50IHRvIHJlY2VpdmUuXG4gICAgICovXG4gICAgZ2V0RGF0YUNoYW5uZWw6IGZ1bmN0aW9uIChjb2xsZWN0aW9uKSB7XG4gICAgICAgIGlmICghY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIGNvbGxlY3Rpb24gdG8gbGlzdGVuIG9uLicpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2RhdGEnLCBhY2NvdW50LCBwcm9qZWN0LCBjb2xsZWN0aW9uXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgLy9UT0RPOiBGaXggYWZ0ZXIgRXBpY2VudGVyIGJ1ZyBpcyByZXNvbHZlZFxuICAgICAgICB2YXIgb2xkc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjYWxsYmFja1dpdGhDbGVhbkRhdGEgPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgICAgICAgICAgICAgIHZhciBtZXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYXlsb2FkLmNoYW5uZWwsXG4gICAgICAgICAgICAgICAgICAgIHN1YlR5cGU6IHBheWxvYWQuZGF0YS5zdWJUeXBlLFxuICAgICAgICAgICAgICAgICAgICBkYXRlOiBwYXlsb2FkLmRhdGEuZGF0ZVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGFjdHVhbERhdGEgPSBwYXlsb2FkLmRhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICBpZiAoYWN0dWFsRGF0YS5kYXRhKSB7IC8vRGVsZXRlIG5vdGlmaWNhdGlvbnMgYXJlIG9uZSBkYXRhLWxldmVsIGJlaGluZCBvZiBjb3Vyc2VcbiAgICAgICAgICAgICAgICAgICAgYWN0dWFsRGF0YSA9IGFjdHVhbERhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIGFjdHVhbERhdGEsIG1ldGEpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aENsZWFuRGF0YSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVQSV9DT09LSUVfS0VZOiAnZXBpY2VudGVyLnByb2plY3QudG9rZW4nLFxuICAgIEVQSV9TRVNTSU9OX0tFWTogJ2VwaWNlbnRlci51c2VyLnNlc3Npb24nLFxuICAgIFNUUkFURUdZX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLXNjZW5hcmlvJ1xufTsiLCIvKipcbiogIyMgUnVuIE1hbmFnZXJcbipcbiogVGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBhY2Nlc3MgdG8gcnVucyBmb3IgeW91ciBwcm9qZWN0LiBUaGlzIGFsbG93cyB5b3UgdG8gcmVhZCBhbmQgdXBkYXRlIHZhcmlhYmxlcywgY2FsbCBvcGVyYXRpb25zLCBldGMuIEFkZGl0aW9uYWxseSwgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLiBTcGVjaWZpY2FsbHksIHlvdSBjYW4gc2VsZWN0IFtydW4gY3JlYXRpb24gc3RyYXRlZ2llcyAocnVsZXMpXSguLi8uLi9zdHJhdGVneS8pIGZvciB3aGljaCBydW5zIGVuZCB1c2VycyBvZiB5b3VyIHByb2plY3Qgd29yayB3aXRoIHdoZW4gdGhleSBsb2cgaW4gdG8geW91ciBwcm9qZWN0LlxuKlxuKiBUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGNyZWF0ZSBuZXcgcnVucywgaW5jbHVkaW5nIHRoZSBFcGljZW50ZXIuanMgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSwgdGhlIFJFU0ZUZnVsIFtSdW4gQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkpIGFuZCB0aGUgW01vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLykuIEhvd2V2ZXIsIGZvciBzb21lIHByb2plY3RzIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gcGljayB1cCB3aGVyZSB0aGUgdXNlciBsZWZ0IG9mZiwgdXNpbmcgYW4gZXhpc3RpbmcgcnVuLiBBbmQgaW4gc29tZSBwcm9qZWN0cywgd2hldGhlciB0byBjcmVhdGUgYSBuZXcgcnVuIG9yIHVzZSBhbiBleGlzdGluZyBvbmUgaXMgY29uZGl0aW9uYWwsIGZvciBleGFtcGxlIGJhc2VkIG9uIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZXhpc3RpbmcgcnVuIG9yIHlvdXIgb3duIGtub3dsZWRnZSBhYm91dCB0aGUgbW9kZWwuIFRoZSBSdW4gTWFuYWdlciBwcm92aWRlcyB0aGlzIGxldmVsIG9mIGNvbnRyb2w6IHlvdXIgY2FsbCB0byBgZ2V0UnVuKClgLCByYXRoZXIgdGhhbiBhbHdheXMgcmV0dXJuaW5nIGEgbmV3IHJ1biwgcmV0dXJucyBhIHJ1biBiYXNlZCBvbiB0aGUgc3RyYXRlZ3kgeW91J3ZlIHNwZWNpZmllZC4gKE5vdGUgdGhhdCBtYW55IG9mIHRoZSBFcGljZW50ZXIgc2FtcGxlIHByb2plY3RzIHVzZSBhIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LCBiZWNhdXNlIGdlbmVyYWxseSB0aGUgc2FtcGxlIHByb2plY3RzIGFyZSBwbGF5ZWQgaW4gb25lIGVuZCB1c2VyIHNlc3Npb24gYW5kIGRvbid0IGNhcmUgYWJvdXQgcnVuIHN0YXRlcyBvciBydW4gc3RyYXRlZ2llcy4pXG4qXG4qXG4qICMjIyBVc2luZyB0aGUgUnVuIE1hbmFnZXIgdG8gY3JlYXRlIGFuZCBhY2Nlc3MgcnVuc1xuKlxuKiBUbyB1c2UgdGhlIFJ1biBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuKlxuKiAgICogYHJ1bmA6IChyZXF1aXJlZCkgUnVuIG9iamVjdC4gTXVzdCBjb250YWluOlxuKiAgICAgICAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICAgICAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4qICAgICAgICogYG1vZGVsYDogVGhlIG5hbWUgb2YgeW91ciBwcmltYXJ5IG1vZGVsIGZpbGUuIChTZWUgbW9yZSBvbiBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4pXG4qICAgICAgICogYHNjb3BlYDogKG9wdGlvbmFsKSBTY29wZSBvYmplY3QgZm9yIHRoZSBydW4sIGZvciBleGFtcGxlIGBzY29wZS5ncm91cGAgd2l0aCB2YWx1ZSBvZiB0aGUgbmFtZSBvZiB0aGUgZ3JvdXAuXG4qICAgICAgICogYHNlcnZlcmA6IChvcHRpb25hbCkgQW4gb2JqZWN0IHdpdGggb25lIGZpZWxkLCBgaG9zdGAuIFRoZSB2YWx1ZSBvZiBgaG9zdGAgaXMgdGhlIHN0cmluZyBgYXBpLmZvcmlvLmNvbWAsIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4qICAgICAgICogYGZpbGVzYDogKG9wdGlvbmFsKSBJZiBhbmQgb25seSBpZiB5b3UgYXJlIHVzaW5nIGEgVmVuc2ltIG1vZGVsIGFuZCB5b3UgaGF2ZSBhZGRpdGlvbmFsIGRhdGEgdG8gcGFzcyBpbiB0byB5b3VyIG1vZGVsLCB5b3UgY2FuIHBhc3MgYSBgZmlsZXNgIG9iamVjdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgZmlsZXMsIGZvciBleGFtcGxlOiBgXCJmaWxlc1wiOiB7XCJkYXRhXCI6IFwibXlFeHRyYURhdGEueGxzXCJ9YC4gKE5vdGUgdGhhdCB5b3UnbGwgYWxzbyBuZWVkIHRvIGFkZCB0aGlzIHNhbWUgZmlsZXMgb2JqZWN0IHRvIHlvdXIgVmVuc2ltIFtjb25maWd1cmF0aW9uIGZpbGVdKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltLykuKSBTZWUgdGhlIFt1bmRlcmx5aW5nIE1vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLyNwb3N0LWNyZWF0aW5nLWEtbmV3LXJ1bi1mb3ItdGhpcy1wcm9qZWN0KSBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbi5cbipcbiogICAqIGBzdHJhdGVneWA6IChvcHRpb25hbCkgUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4qXG4qICAgKiBgc2Vzc2lvbktleWA6IChvcHRpb25hbCkgTmFtZSBvZiBicm93c2VyIGNvb2tpZSBpbiB3aGljaCB0byBzdG9yZSBydW4gaW5mb3JtYXRpb24sIGluY2x1ZGluZyBydW4gaWQuIE1hbnkgY29uZGl0aW9uYWwgc3RyYXRlZ2llcywgaW5jbHVkaW5nIHRoZSBwcm92aWRlZCBzdHJhdGVnaWVzLCByZWx5IG9uIHRoaXMgYnJvd3NlciBjb29raWUgdG8gc3RvcmUgdGhlIHJ1biBpZCBhbmQgaGVscCBtYWtlIHRoZSBkZWNpc2lvbiBvZiB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZS4gVGhlIG5hbWUgb2YgdGhpcyBjb29raWUgZGVmYXVsdHMgdG8gYGVwaWNlbnRlci1zY2VuYXJpb2AgYW5kIGNhbiBiZSBzZXQgd2l0aCB0aGUgYHNlc3Npb25LZXlgIHBhcmFtZXRlci5cbipcbipcbiogQWZ0ZXIgaW5zdGFudGlhdGluZyBhIFJ1biBNYW5hZ2VyLCBtYWtlIGEgY2FsbCB0byBgZ2V0UnVuKClgIHdoZW5ldmVyIHlvdSBuZWVkIHRvIGFjY2VzcyBhIHJ1biBmb3IgdGhpcyBlbmQgdXNlci4gVGhlIGBSdW5NYW5hZ2VyLnJ1bmAgY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLiBUaGUgUnVuIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBhY2Nlc3MgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy5cbipcbiogKipFeGFtcGxlKipcbipcbiogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiogICAgICAgICAgIHJ1bjoge1xuKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJyxcbiogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiogICAgICAgICAgIH0sXG4qICAgICAgICAgICBzdHJhdGVneTogJ2Fsd2F5cy1uZXcnLFxuKiAgICAgICAgICAgc2Vzc2lvbktleTogJ2VwaWNlbnRlci1zZXNzaW9uJ1xuKiAgICAgICB9KTtcbiogICAgICAgcm0uZ2V0UnVuKClcbiogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuKiAgICAgICAgICAgICAgIC8vIHRoZSByZXR1cm4gdmFsdWUgb2YgZ2V0UnVuKCkgaXMgYSBydW4gb2JqZWN0XG4qICAgICAgICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gYWxzbyBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuKiAgICAgICAgICAgICAgIC8vIHNvIGFueSBSdW4gU2VydmljZSBtZXRob2QgaXMgdmFsaWQgaGVyZVxuKiAgICAgICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiogICAgICAgfSlcbipcbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBzdHJhdGVnaWVzTWFwID0gcmVxdWlyZSgnLi9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcCcpO1xudmFyIHNwZWNpYWxPcGVyYXRpb25zID0gcmVxdWlyZSgnLi9zcGVjaWFsLW9wZXJhdGlvbnMnKTtcbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcblxuXG5mdW5jdGlvbiBwYXRjaFJ1blNlcnZpY2Uoc2VydmljZSwgbWFuYWdlcikge1xuICAgIGlmIChzZXJ2aWNlLnBhdGNoZWQpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuXG4gICAgdmFyIG9yaWcgPSBzZXJ2aWNlLmRvO1xuICAgIHNlcnZpY2UuZG8gPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHJlc2VydmVkT3BzID0gT2JqZWN0LmtleXMoc3BlY2lhbE9wZXJhdGlvbnMpO1xuICAgICAgICBpZiAocmVzZXJ2ZWRPcHMuaW5kZXhPZihvcGVyYXRpb24pID09PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG9yaWcuYXBwbHkoc2VydmljZSwgYXJndW1lbnRzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT3BlcmF0aW9uc1tvcGVyYXRpb25dLmNhbGwoc2VydmljZSwgcGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBzZXJ2aWNlLnBhdGNoZWQgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHNlcnZpY2U7XG59XG5cblxuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cblxuICAgIHN0cmF0ZWd5OiAnbmV3LWlmLWluaXRpYWxpemVkJ1xufTtcblxuZnVuY3Rpb24gUnVuTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMucnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICB0aGlzLnJ1biA9IHRoaXMub3B0aW9ucy5ydW47XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5ydW4gPSBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMucnVuKTtcbiAgICB9XG5cbiAgICBwYXRjaFJ1blNlcnZpY2UodGhpcy5ydW4sIHRoaXMpO1xuXG4gICAgdmFyIFN0cmF0ZWd5Q3RvciA9IHR5cGVvZiB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgPT09ICdmdW5jdGlvbicgPyB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgOiBzdHJhdGVnaWVzTWFwW3RoaXMub3B0aW9ucy5zdHJhdGVneV07XG5cbiAgICBpZiAoIVN0cmF0ZWd5Q3Rvcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NwZWNpZmllZCBydW4gY3JlYXRpb24gc3RyYXRlZ3kgd2FzIGludmFsaWQ6JywgdGhpcy5vcHRpb25zLnN0cmF0ZWd5KTtcbiAgICB9XG5cbiAgICB0aGlzLnN0cmF0ZWd5ID0gbmV3IFN0cmF0ZWd5Q3Rvcih0aGlzLnJ1biwgdGhpcy5vcHRpb25zKTtcbn1cblxuUnVuTWFuYWdlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSAnZ29vZCcgcnVuLlxuICAgICAqXG4gICAgICogQSBnb29kIHJ1biBpcyBkZWZpbmVkIGJ5IHRoZSBzdHJhdGVneS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBzdHJhdGVneSBpcyBgYWx3YXlzLW5ld2AsIHRoZSBjYWxsXG4gICAgICogdG8gYGdldFJ1bigpYCBhbHdheXMgcmV0dXJucyBhIG5ld2x5IGNyZWF0ZWQgcnVuOyBpZiB0aGUgc3RyYXRlZ3kgaXMgYG5ldy1pZi1wZXJzaXN0ZWRgLFxuICAgICAqIGBnZXRSdW4oKWAgY3JlYXRlcyBhIG5ldyBydW4gaWYgdGhlIHByZXZpb3VzIHJ1biBpcyBpbiBhIHBlcnNpc3RlZCBzdGF0ZSwgb3RoZXJ3aXNlXG4gICAgICogaXQgcmV0dXJucyB0aGUgcHJldmlvdXMgcnVuLiBTZWUgW1J1biBNYW5hZ2VyIFN0cmF0ZWdpZXNdKC4uLy4uL3N0cmF0ZWd5LykgZm9yIG1vcmUgb24gc3RyYXRlZ2llcy5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5nZXRSdW4oKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqIEByZXR1cm4geyRwcm9taXNlfSBQcm9taXNlIHRvIGNvbXBsZXRlIHRoZSBjYWxsLlxuICAgICAqL1xuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdHJhdGVneVxuICAgICAgICAgICAgICAgIC5nZXRSdW4oKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSBuZXcgcnVuLCByZWdhcmRsZXNzIG9mIHN0cmF0ZWd5OiBmb3JjZSBjcmVhdGlvbiBvZiBhIG5ldyBydW4uXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgcm0ucmVzZXQoKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIChuZXcpIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBydW5TZXJ2aWNlT3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgUnVuIFNlcnZpY2UuIFNlZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBmb3IgbW9yZS5cbiAgICAgKi9cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5LnJlc2V0KHJ1blNlcnZpY2VPcHRpb25zKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJ1bk1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIC8vIGFsd2F5cyBjcmVhdGUgYSBuZXcgcnVuIVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1ha2VTZXEgPSByZXF1aXJlKCcuLi8uLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFNlc3Npb25TdG9yZSA9IHJlcXVpcmUoJy4uLy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBVcmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgc2Vzc2lvblN0b3JlID0gbmV3IFNlc3Npb25TdG9yZSh7fSk7XG52YXIgdXJsU2VydmljZSA9IG5ldyBVcmxTZXJ2aWNlKCk7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9rZXktbmFtZXMnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHNlc3Npb25LZXk6IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZLFxuICAgIHBhdGg6ICcnXG59O1xuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBwYXRoKSB7XG4gICAgaWYgKCFwYXRoKSB7XG4gICAgICAgIGlmICghdXJsU2VydmljZS5pc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgICAgICBwYXRoID0gJy8nICsgW3VybFNlcnZpY2UuYXBwUGF0aCwgdXJsU2VydmljZS5hY2NvdW50UGF0aCwgdXJsU2VydmljZS5wcm9qZWN0UGF0aF0uam9pbignLycpO1xuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHdlIGRvbid0IGdldCBjb25zZWN1dGVpdmUgJy8nIHNvIHdlIGhhdmUgYSB2YWxpZCBwYXRoIGZvciB0aGUgc2Vzc2lvblxuICAgICAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZSgvXFwvezIsfS9nLCcvJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYXRoID0gJyc7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gc2V0IHRoZSBzZWVzaW9uS2V5IGZvciB0aGUgcnVuXG4gICAgc2Vzc2lvblN0b3JlLnNldChzZXNzaW9uS2V5LCBKU09OLnN0cmluZ2lmeSh7IHJ1bklkOiBydW4uaWQgfSksIHsgcm9vdDogcGF0aCB9KTtcbn1cblxuLyoqXG4qIENvbmRpdGlvbmFsIENyZWF0aW9uIFN0cmF0ZWd5XG4qIFRoaXMgc3RyYXRlZ3kgd2lsbCB0cnkgdG8gZ2V0IHRoZSBydW4gc3RvcmVkIGluIHRoZSBjb29raWUgYW5kXG4qIGV2YWx1YXRlIGlmIG5lZWRzIHRvIGNyZWF0ZSBhIG5ldyBydW4gYnkgY2FsbGluZyB0aGUgJ2NvbmRpdGlvbicgZnVuY3Rpb25cbiovXG5cbi8qIGpzaGludCBlcW51bGw6IHRydWUgKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KHJ1blNlcnZpY2UsIGNvbmRpdGlvbiwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChjb25kaXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb25kaXRpb25hbCBzdHJhdGVneSBuZWVkcyBhIGNvbmRpdGlvbiB0byBjcmVhdGV0ZSBhIHJ1bicpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fYXV0aCA9IG5ldyBBdXRoTWFuYWdlcigpO1xuICAgICAgICB0aGlzLnJ1biA9IG1ha2VTZXEocnVuU2VydmljZSk7XG4gICAgICAgIHRoaXMuY29uZGl0aW9uID0gdHlwZW9mIGNvbmRpdGlvbiAhPT0gJ2Z1bmN0aW9uJyA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNvbmRpdGlvbjsgfSA6IGNvbmRpdGlvbjtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9LFxuXG4gICAgcnVuT3B0aW9uc1dpdGhTY29wZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdXNlclNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiB1c2VyU2Vzc2lvbi5ncm91cE5hbWUgfVxuICAgICAgICB9LCB0aGlzLnJ1bk9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBvcHQgPSB0aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5ydW5cbiAgICAgICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgc2V0UnVuSW5TZXNzaW9uKF90aGlzLm9wdGlvbnMuc2Vzc2lvbktleSwgcnVuLCBfdGhpcy5vcHRpb25zLnBhdGgpO1xuICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmUuZ2V0KHRoaXMub3B0aW9ucy5zZXNzaW9uS2V5KSk7XG5cbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRBbmRDaGVjayhydW5TZXNzaW9uKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgX2xvYWRBbmRDaGVjazogZnVuY3Rpb24gKHJ1blNlc3Npb24pIHtcbiAgICAgICAgdmFyIHNob3VsZENyZWF0ZSA9IGZhbHNlO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1blxuICAgICAgICAgICAgLmxvYWQocnVuU2Vzc2lvbi5ydW5JZCwgbnVsbCwge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uIChydW4sIG1zZywgaGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBzaG91bGRDcmVhdGUgPSBfdGhpcy5jb25kaXRpb24uY2FsbChfdGhpcywgcnVuLCBoZWFkZXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIGlmIChzaG91bGRDcmVhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9wdCA9IF90aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgbmVlZCB0byBkbyB0aGlzLCBvbiB0aGUgb3JpZ2luYWwgcnVuU2VydmljZSAoaWUgbm90IHNlcXVlbmNpYWxpemVkKVxuICAgICAgICAgICAgICAgICAgICAvLyBzbyB3ZSBkb24ndCBnZXQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1bi5vcmlnaW5hbC5jcmVhdGUob3B0KVxuICAgICAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oX3RoaXMub3B0aW9ucy5zZXNzaW9uS2V5LCBydW4pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnN0YXJ0KCk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSAgPSBydW5TZXJ2aWNlO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSBuZXdseSBjcmVhdGVkIHJ1blxuICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoKS5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSh0aGlzLnJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vaWRlbnRpdHktc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0b3JlOiB7XG4gICAgICAgIHN5bmNocm9ub3VzOiB0cnVlXG4gICAgfVxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcblxuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMud29ybGRBcGkgPSBuZXcgV29ybGRBcGlBZGFwdGVyKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciB3b3JsZEFwaSA9IHRoaXMud29ybGRBcGk7XG4gICAgICAgIHZhciBtb2RlbCA9IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAoIWN1clVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDAsIGVycm9yOiAnV2UgbmVlZCBhbiBhdXRoZW50aWNhdGVkIHVzZXIgdG8gam9pbiBhIG11bHRpcGxheWVyIHdvcmxkLiAoRVJSOiBubyB1c2VySWQgaW4gc2Vzc2lvbiknIH0sIHNlc3Npb24pLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsb2FkUnVuRnJvbVdvcmxkID0gZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDQsIGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IGluIGFueSB3b3JsZC4nIH0sIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oX3RoaXMuX2xvYWRSdW4pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgZHRkLnJlamVjdChlcnJvciwgc2Vzc2lvbiwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIF9sb2FkUnVuOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIFN0YXRlQXBpID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICAgICAgdGhpcy5fc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICAgICAgdGhpcy5zdGF0ZUFwaSA9IG5ldyBTdGF0ZUFwaSgpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZEFuZENoZWNrID0gdGhpcy5fbG9hZEFuZENoZWNrLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVSdW4gPSB0aGlzLl9yZXN0b3JlUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2dldEFsbFJ1bnMgPSB0aGlzLl9nZXRBbGxSdW5zLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0QWxsUnVucygpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9sb2FkQW5kQ2hlY2spO1xuICAgIH0sXG5cbiAgICBfZ2V0QWxsUnVuczogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2UodGhpcy5fc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9Jyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5xdWVyeSh7XG4gICAgICAgICAgICAndXNlci5pZCc6IHNlc3Npb24udXNlcklkIHx8ICcwMDAwJyxcbiAgICAgICAgICAgICdzY29wZS5ncm91cCc6IHNlc3Npb24uZ3JvdXBOYW1lXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVucykge1xuICAgICAgICBpZiAoIXJ1bnMgfHwgIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGVDb21wID0gZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIuZGF0ZSkgLSBuZXcgRGF0ZShhLmRhdGUpOyB9O1xuICAgICAgICB2YXIgbGF0ZXN0UnVuID0gcnVucy5zb3J0KGRhdGVDb21wKVswXTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHNob3VsZFJlcGxheSA9IGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGxhdGVzdFJ1bi5pZCwgbnVsbCwge1xuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVwbGF5ID0gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2hvdWxkUmVwbGF5ID8gX3RoaXMuX3Jlc3RvcmVSdW4ocnVuLmlkKSA6IHJ1bjtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9yZXN0b3JlUnVuOiBmdW5jdGlvbiAocnVuSWQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVBcGkucmVwbGF5KHsgcnVuSWQ6IHJ1bklkIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJ1bihyZXNwLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW4ubG9hZChpZCwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgICduZXctaWYtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLFxuICAgICduZXctaWYtcGVyc2lzdGVkJzogcmVxdWlyZSgnLi9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1taXNzaW5nJzogcmVxdWlyZSgnLi9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpLFxuICAgICdhbHdheXMtbmV3JzogcmVxdWlyZSgnLi9hbHdheXMtbmV3LXN0cmF0ZWd5JyksXG4gICAgJ211bHRpcGxheWVyJzogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdwZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXInOiByZXF1aXJlKCcuL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneScpLFxuICAgICdub25lJzogcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgdmFsaWRGaWx0ZXI6IHsgc2F2ZWQ6IHRydWUgfVxufTtcblxuZnVuY3Rpb24gU2NlbmFyaW9NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMucnVuU2VydmljZSA9IHRoaXMub3B0aW9ucy5ydW4gfHwgbmV3IFJ1blNlcnZpY2UodGhpcy5vcHRpb25zKTtcbn1cblxuU2NlbmFyaW9NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy52YWxpZEZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlcik7XG4gICAgfSxcblxuICAgIGxvYWRWYXJpYWJsZXM6IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UucXVlcnkodGhpcy5maWx0ZXIsIHsgaW5jbHVkZTogdmFycyB9KTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgbWV0YSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2VydmljZShydW4pLnNhdmUoJC5leHRlbmQodHJ1ZSwge30sIHsgc2F2ZWQ6IHRydWUgfSwgbWV0YSkpO1xuICAgIH0sXG5cbiAgICBhcmNoaXZlOiBmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSh7IHNhdmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuXG4gICAgX2dldFNlcnZpY2U6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW4gfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdvYmplY3QnICYmIHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NhdmUgbWV0aG9kIHJlcXVpcmVzIGEgcnVuIHNlcnZpY2Ugb3IgYSBydW5JZCcpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW5JZCB9KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICByZXNldDogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucywgbWFuYWdlcikge1xuICAgICAgICByZXR1cm4gbWFuYWdlci5yZXNldChvcHRpb25zKTtcbiAgICB9XG59O1xuIiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9ICByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG4vLyB2YXIgZGVmYXVsdHMgPSB7XG4vLyAgYWNjb3VudDogJycsXG4vLyAgcHJvamVjdDogJycsXG4vLyAgZ3JvdXA6ICcnLFxuLy8gIHRyYW5zcG9ydDoge1xuLy8gIH1cbi8vIH07XG5cblxuZnVuY3Rpb24gYnVpbGRTdHJhdGVneSh3b3JsZElkLCBkdGQpIHtcblxuICAgIHJldHVybiBmdW5jdGlvbiBDdG9yKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICAkLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm90IGltcGxlbWVudGQuIE5lZWQgYXBpIGNoYW5nZXMnKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlLmNhbGwodGhpcywgcnVuLCBfdGhpcy5ydW5TZXJ2aWNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcklkYCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSBncm91cCBmb3IgdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bih7bW9kZWw6ICdteU1vZGVsLnB5J30pXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBtb2RlbGAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgbW9kZWwgZmlsZS4gUmVxdWlyZWQgaWYgbm90IGFscmVhZHkgcGFzc2VkIGluIGFzIGBydW4ubW9kZWxgIHdoZW4gdGhlIFdvcmxkIE1hbmFnZXIgaXMgY3JlYXRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgX3RoaXMub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJtLmdldFJ1bigpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHJ1biwgcm0ucnVuU2VydmljZSwgcm0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5nZXRDdXJyZW50V29ybGQoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bik7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIGFwaSk7XG59O1xuIiwiLyoqXG4gKiAjI0ZpbGUgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGlzIGlzIHVzZWQgdG8gdXBsb2FkL2Rvd25sb2FkIGZpbGVzIGRpcmVjdGx5IG9udG8gRXBpY2VudGVyLCBhbmFsb2dvdXMgdG8gdXNpbmcgdGhlIEZpbGUgTWFuYWdlciBVSSBpbiBFcGljZW50ZXIgZGlyZWN0bHkgb3IgU0ZUUGluZyBmaWxlcyBpbi4gVGhlIEFzc2V0IEFQSSBpcyB0eXBpY2FsbHkgdXNlZCBmb3IgYWxsIHByb2plY3QgdXNlLWNhc2VzLCBhbmQgaXQncyB1bmxpa2VseSB0aGlzIEZpbGUgU2VydmljZSB3aWxsIGJlIHVzZWQgZGlyZWN0bHkgZXhjZXB0IGJ5IEFkbWluIHRvb2xzIChlLmcuIEZsb3cgSW5zcGVjdG9yKS5cbiAqXG4gKiBQYXJ0aWFsbHkgaW1wbGVtZW50ZWQuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCBzdG9yZS5nZXQoJ2VwaWNlbnRlci50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZmlsZScpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQXN5bmNBUEkgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgYSBkaXJlY3RvcnkgbGlzdGluZywgb3IgY29udGVudHMgb2YgYSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGZpbGVQYXRoYCAgIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZm9sZGVyVHlwZWAgT25lIG9mIE1vZGVsfFN0YXRpY3xOb2RlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBnZXRDb250ZW50czogZnVuY3Rpb24gKGZpbGVQYXRoLCBmb2xkZXJUeXBlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IGZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbi8vIHZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGtleU5hbWVzID0gcmVxdWlyZSgnLi4vbWFuYWdlcnMva2V5LW5hbWVzJyk7XG5cbnZhciBhcGlFbmRwb2ludCA9ICdhc3NldCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZShzdG9yZS5nZXQoa2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZKSB8fCAne30nKTtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9DT09LSUVfS0VZKSB8fCAnJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gRGVmYXVsdHMgdG8gc2Vzc2lvbidzIGBncm91cE5hbWVgLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogc2Vzc2lvbi51c2VySWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgc2NvcGUgZm9yIHRoZSBhc3NldC4gVmFsaWQgdmFsdWVzIGFyZTogYHVzZXJgLCBgZ3JvdXBgLCBhbmQgYHByb2plY3RgLiBTZWUgYWJvdmUgZm9yIHRoZSByZXF1aXJlZCBwZXJtaXNzaW9ucyB0byB3cml0ZSB0byBlYWNoIHNjb3BlLiBEZWZhdWx0cyB0byBgdXNlcmAsIG1lYW5pbmcgdGhlIGN1cnJlbnQgZW5kIHVzZXIgb3IgYSBmYWNpbGl0YXRvciBpbiB0aGUgZW5kIHVzZXIncyBncm91cCBjYW4gZWRpdCB0aGUgYXNzZXQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBzY29wZTogJ3VzZXInLFxuICAgICAgICAvKipcbiAgICAgICAgICogRGV0ZXJtaW5lcyBpZiBhIHJlcXVlc3QgdG8gbGlzdCB0aGUgYXNzZXRzIGluIGEgc2NvcGUgaW5jbHVkZXMgdGhlIGNvbXBsZXRlIFVSTCBmb3IgZWFjaCBhc3NldCAoYHRydWVgKSwgb3Igb25seSB0aGUgZmlsZSBuYW1lcyBvZiB0aGUgYXNzZXRzIChgZmFsc2VgKS4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGZ1bGxVcmw6IHRydWUsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgdHJhbnNwb3J0IG9iamVjdCBjb250YWlucyB0aGUgb3B0aW9ucyBwYXNzZWQgdG8gdGhlIFhIUiByZXF1ZXN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7XG4gICAgICAgICAgICBwcm9jZXNzRGF0YTogZmFsc2VcbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIGFzc2V0QXBpUGFyYW1zID0gWydlbmNvZGluZycsICdkYXRhJywgJ2NvbnRlbnRUeXBlJ107XG4gICAgdmFyIHNjb3BlQ29uZmlnID0ge1xuICAgICAgICB1c2VyOiBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSxcbiAgICAgICAgZ3JvdXA6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10sXG4gICAgICAgIHByb2plY3Q6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0J10sXG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZUZpbGVuYW1lID0gZnVuY3Rpb24gKGZpbGVuYW1lKSB7XG4gICAgICAgIGlmICghZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZmlsZW5hbWUgaXMgbmVlZGVkLicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZVVybFBhcmFtcyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICBpZiAoIXBhcnRLZXlzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Njb3BlIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cblxuICAgICAgICAkLmVhY2gocGFydEtleXMsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICghb3B0aW9uc1t0aGlzXSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzICsgJyBwYXJhbWV0ZXIgaXMgbmVlZGVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgdmFyIGJ1aWxkVXJsID0gZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgIHZhbGlkYXRlVXJsUGFyYW1zKG9wdGlvbnMpO1xuICAgICAgICB2YXIgcGFydEtleXMgPSBzY29wZUNvbmZpZ1tvcHRpb25zLnNjb3BlXTtcbiAgICAgICAgdmFyIHBhcnRzID0gJC5tYXAocGFydEtleXMsIGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zW2tleV07XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgcHJldmVudHMgYWRkaW5nIGEgdHJhaWxpbmcgLyBpbiB0aGUgVVJMIGFzIHRoZSBBc3NldCBBUElcbiAgICAgICAgICAgIC8vIGRvZXMgbm90IHdvcmsgY29ycmVjdGx5IHdpdGggaXRcbiAgICAgICAgICAgIGZpbGVuYW1lID0gJy8nICsgZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHBhcnRzLmpvaW4oJy8nKSArIGZpbGVuYW1lO1xuICAgIH07XG5cbiAgICAvLyBQcml2YXRlIGZ1bmN0aW9uLCBhbGwgcmVxdWVzdHMgZm9sbG93IGEgbW9yZSBvciBsZXNzIHNhbWUgYXBwcm9hY2ggdG9cbiAgICAvLyB1c2UgdGhlIEFzc2V0IEFQSSBhbmQgdGhlIGRpZmZlcmVuY2UgaXMgdGhlIEhUVFAgdmVyYlxuICAgIC8vXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBtZXRob2RgIChSZXF1aXJlZCkgSFRUUCB2ZXJiXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS9yZXBsYWNlL2NyZWF0ZVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUElcbiAgICAvLyBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgdmFyIHVwbG9hZCA9IGZ1bmN0aW9uIChtZXRob2QsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVGaWxlbmFtZShmaWxlbmFtZSk7XG4gICAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgcGFyYW1ldGVyIGlzIGNsZWFuXG4gICAgICAgIG1ldGhvZCA9IG1ldGhvZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB2YXIgY29udGVudFR5cGUgPSBwYXJhbXMgaW5zdGFuY2VvZiBGb3JtRGF0YSA9PT0gdHJ1ZSA/IGZhbHNlIDogJ2FwcGxpY2F0aW9uL2pzb24nO1xuICAgICAgICBpZiAoY29udGVudFR5cGUgPT09ICdhcHBsaWNhdGlvbi9qc29uJykge1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIGFzc2V0QXBpUGFyYW1zKTtcbiAgICAgICAgfSBlbHNlIHsgLy8gZWxzZSB3ZSdyZSBzZW5kaW5nIGZvcm0gZGF0YSB3aGljaCBnb2VzIGRpcmVjdGx5IGluIHJlcXVlc3QgYm9keVxuICAgICAgICAgICAgLy8gRm9yIG11bHRpcGFydC9mb3JtLWRhdGEgdXBsb2FkcyB0aGUgZmlsZW5hbWUgaXMgbm90IHNldCBpbiB0aGUgVVJMLFxuICAgICAgICAgICAgLy8gaXQncyBnZXR0aW5nIHBpY2tlZCBieSB0aGUgRm9ybURhdGEgZmllbGQgZmlsZW5hbWUuXG4gICAgICAgICAgICBmaWxlbmFtZSA9IG1ldGhvZCA9PT0gJ3Bvc3QnIHx8IG1ldGhvZCA9PT0gJ3B1dCcgPyAnJyA6IGZpbGVuYW1lO1xuICAgICAgICB9XG4gICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCwgY29udGVudFR5cGU6IGNvbnRlbnRUeXBlIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwW21ldGhvZF0ocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS4gVGhlIHNlcnZlciByZXR1cm5zIGFuIGVycm9yIChzdGF0dXMgY29kZSBgNDA5YCwgY29uZmxpY3QpIGlmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLCBzb1xuICAgICAgICAqIGNoZWNrIGZpcnN0IHdpdGggYSBgbGlzdCgpYCBvciBhIGBnZXQoKWAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBhYSA9IG5ldyBGLnNlcnZpY2UuQXNzZXQoe1xuICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAgICAqICAgICAgICAgIHVzZXJJZDogJydcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAgICAgICAgKiAgICAgICBhYS5jcmVhdGUoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gICAgICAgICogICAgICAgICAgIGNvbnRlbnRUeXBlOiAndGV4dC9wbGFpbidcbiAgICAgICAgKiAgICAgICB9LCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyBhbHRlcm5hdGl2ZWx5LCBjcmVhdGUgYSBuZXcgYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJ1cGxvYWQtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5VcGxvYWQgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3VwbG9hZC1maWxlJykub24oJ3N1Ym1pdCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLmNyZWF0ZShmaWxlbmFtZSwgZGF0YSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gY3JlYXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUEkuIFJlcXVpcmVkIGlmIHRoZSBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYCwgb3RoZXJ3aXNlIGlnbm9yZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZW5jb2RpbmdgIEVpdGhlciBgSEVYYCBvciBgQkFTRV82NGAuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmRhdGFgIFRoZSBlbmNvZGVkIGRhdGEgZm9yIHRoZSBmaWxlLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5jb250ZW50VHlwZWAgVGhlIG1pbWUgdHlwZSBvZiB0aGUgZmlsZS4gT3B0aW9uYWwuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3Bvc3QnLCBmaWxlbmFtZSwgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGEgZmlsZSBmcm9tIHRoZSBBc3NldCBBUEksIGZldGNoaW5nIHRoZSBhc3NldCBjb250ZW50LiAoVG8gZ2V0IGEgbGlzdFxuICAgICAgICAqIG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZSwgdXNlIGBsaXN0KClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byByZXRyaWV2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBnZXRTZXJ2aWNlT3B0aW9ucyA9IF9waWNrKHNlcnZpY2VPcHRpb25zLCBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSk7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBnZXRTZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBsaXN0IG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5saXN0KHsgZnVsbFVybDogdHJ1ZSB9KS50aGVuKGZ1bmN0aW9uKGZpbGVMaXN0KXtcbiAgICAgICAgKiAgICAgICAgICAgY29uc29sZS5sb2coJ2FycmF5IG9mIGZpbGVzID0gJywgZmlsZUxpc3QpO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5zY29wZWAgKE9wdGlvbmFsKSBUaGUgc2NvcGUgKGB1c2VyYCwgYGdyb3VwYCwgYHByb2plY3RgKS5cbiAgICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGBvcHRpb25zLmZ1bGxVcmxgIChPcHRpb25hbCkgRGV0ZXJtaW5lcyBpZiB0aGUgbGlzdCBvZiBhc3NldHMgaW4gYSBzY29wZSBpbmNsdWRlcyB0aGUgY29tcGxldGUgVVJMIGZvciBlYWNoIGFzc2V0IChgdHJ1ZWApLCBvciBvbmx5IHRoZSBmaWxlIG5hbWVzIG9mIHRoZSBhc3NldHMgKGBmYWxzZWApLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybCgnJywgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuICAgICAgICAgICAgdmFyIGZ1bGxVcmwgPSBnZXRPcHRpb25zLmZ1bGxVcmw7XG5cbiAgICAgICAgICAgIGlmICghZnVsbFVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZnVsbFBhdGhGaWxlcyA9ICQubWFwKGZpbGVzLCBmdW5jdGlvbiAoZmlsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoZnVsbFBhdGhGaWxlcywgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlcGxhY2VzIGFuIGV4aXN0aW5nIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyByZXBsYWNlIGFuIGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLnJlcGxhY2UoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhObFkyOXVaQ0IwWlhOMElHWnBiR1V1JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJyZXBsYWNlLWZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwicmVwbGFjZS1maWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5SZXBsYWNlIG15RmlsZTwvYnV0dG9uPlxuICAgICAgICAqICAgICAgIC8vIDwvZm9ybT5cbiAgICAgICAgKiAgICAgICAvL1xuICAgICAgICAqICAgICAgICQoJyNyZXBsYWNlLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI3JlcGxhY2UtZmlsZW5hbWUnKS52YWwoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICAgICAgICAqICAgICAgICAgIGRhdGEuYXBwZW5kKCdmaWxlJywgaW5wdXRDb250cm9sLmZpbGVzWzBdLCBmaWxlbmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICBhYS5yZXBsYWNlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgYmVpbmcgcmVwbGFjZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgcmVwbGFjZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3B1dCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5kZWxldGUoc2FtcGxlRmlsZU5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ2RlbGV0ZScsIGZpbGVuYW1lLCB7fSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYXNzZXRVcmw6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlIHByb3ZpZGVzIG1ldGhvZHMgZm9yIGxvZ2dpbmcgaW4gYW5kIGxvZ2dpbmcgb3V0LiBPbiBsb2dpbiwgdGhpcyBzZXJ2aWNlIGNyZWF0ZXMgYW5kIHJldHVybnMgYSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAqXG4gKiBVc2VyIGFjY2VzcyB0b2tlbnMgYXJlIHJlcXVpcmVkIGZvciBlYWNoIGNhbGwgdG8gRXBpY2VudGVyLiAoU2VlIFtQcm9qZWN0IEFjY2Vzc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4pXG4gKlxuICogSWYgeW91IG5lZWQgYWRkaXRpb25hbCBmdW5jdGlvbmFsaXR5IC0tIHN1Y2ggYXMgdHJhY2tpbmcgc2Vzc2lvbiBpbmZvcm1hdGlvbiwgZWFzaWx5IHJldHJpZXZpbmcgdGhlIHVzZXIgdG9rZW4sIG9yIGdldHRpbmcgdGhlIGdyb3VwcyB0byB3aGljaCBhbiBlbmQgdXNlciBiZWxvbmdzIC0tIGNvbnNpZGVyIHVzaW5nIHRoZSBbQXV0aG9yaXphdGlvbiBNYW5hZ2VyXSguLi9hdXRoLW1hbmFnZXIvKSBpbnN0ZWFkLlxuICpcbiAqICAgICAgdmFyIGF1dGggPSBuZXcgRi5zZXJ2aWNlLkF1dGgoKTtcbiAqICAgICAgYXV0aC5sb2dpbih7IHVzZXJOYW1lOiAnanNtaXRoQGFjbWVzaW11bGF0aW9ucy5jb20nLFxuICogICAgICAgICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyB9KTtcbiAqICAgICAgYXV0aC5sb2dvdXQoKTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VyTmFtZTogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFzc3dvcmQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gUmVxdWlyZWQgaWYgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdhdXRoZW50aWNhdGlvbicpXG4gICAgfSk7XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvZ3MgdXNlciBpbiwgcmV0dXJuaW5nIHRoZSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAgICAgICAgICpcbiAgICAgICAgICogSWYgbm8gYHVzZXJOYW1lYCBvciBgcGFzc3dvcmRgIHdlcmUgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLCB0aGV5IGFyZSByZXF1aXJlZCBpbiB0aGUgYG9wdGlvbnNgIGhlcmUuIElmIG5vIGBhY2NvdW50YCB3YXMgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zIGFuZCB0aGUgYHVzZXJOYW1lYCBpcyBmb3IgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGUgYGFjY291bnRgIGlzIHJlcXVpcmVkIGFzIHdlbGwuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgYXV0aC5sb2dpbih7XG4gICAgICAgICAqICAgICAgICAgIHVzZXJOYW1lOiAnanNtaXRoJyxcbiAgICAgICAgICogICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcsXG4gICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyB9KVxuICAgICAgICAgKiAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhcInVzZXIgYWNjZXNzIHRva2VuIGlzOiBcIiwgdG9rZW4uYWNjZXNzX3Rva2VuKTtcbiAgICAgICAgICogICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHN1Y2Nlc3M6ICQubm9vcCB9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBpZiAoIWh0dHBPcHRpb25zLnVzZXJOYW1lIHx8ICFodHRwT3B0aW9ucy5wYXNzd29yZCkge1xuICAgICAgICAgICAgICAgIHZhciByZXNwID0geyBzdGF0dXM6IDQwMSwgc3RhdHVzTWVzc2FnZTogJ05vIHVzZXJuYW1lIG9yIHBhc3N3b3JkIHNwZWNpZmllZC4nIH07XG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvci5jYWxsKHRoaXMsIHJlc3ApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVqZWN0KHJlc3ApLnByb21pc2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHBvc3RQYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgdXNlck5hbWU6IGh0dHBPcHRpb25zLnVzZXJOYW1lLFxuICAgICAgICAgICAgICAgIHBhc3N3b3JkOiBodHRwT3B0aW9ucy5wYXNzd29yZCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoaHR0cE9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vcGFzcyBpbiBudWxsIGZvciBhY2NvdW50IHVuZGVyIG9wdGlvbnMgaWYgeW91IGRvbid0IHdhbnQgaXQgdG8gYmUgc2VudFxuICAgICAgICAgICAgICAgIHBvc3RQYXJhbXMuYWNjb3VudCA9IGh0dHBPcHRpb25zLmFjY291bnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocG9zdFBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2dzIHVzZXIgb3V0IGZyb20gc3BlY2lmaWVkIGFjY291bnRzLlxuICAgICAgICAgKiBFcGljZW50ZXIgbG9nb3V0IGlzIG5vdCBpbXBsZW1lbnRlZCB5ZXQsIGFkZGVkIGEgZHVtbXkgcHJvbWlzZSB0aGF0IGdldHMgYXV0b21hdGljYWxseSByZXNvbHZlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBhdXRoLmxvZ291dCgpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2dvdXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgZHRkLnJlc29sdmUoKTtcbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqICMjIENoYW5uZWwgU2VydmljZVxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBDaGFubmVsIFNlcnZpY2UgaXMgYSBidWlsZGluZyBibG9jayBmb3IgdGhpcyBmdW5jdGlvbmFsaXR5LiBJdCBjcmVhdGVzIGEgcHVibGlzaC1zdWJzY3JpYmUgb2JqZWN0LCBhbGxvd2luZyB5b3UgdG8gcHVibGlzaCBtZXNzYWdlcywgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzLCBvciB1bnN1YnNjcmliZSBmcm9tIG1lc3NhZ2VzIGZvciBhIGdpdmVuICd0b3BpYycgb24gYSBgJC5jb21ldGRgIHRyYW5zcG9ydCBpbnN0YW5jZS5cbiAqXG4gKiBUeXBpY2FsbHksIHlvdSB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgdG8gY3JlYXRlIG9yIHJldHJpZXZlIGNoYW5uZWxzLCB0aGVuIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gbGlzdGVuIHRvIG9yIHVwZGF0ZSBkYXRhLiAoRm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZCBvbiBFcGljZW50ZXIncyBwdXNoIGNoYW5uZWwsIHNlZSB0aGUgaW50cm9kdWN0b3J5IG5vdGVzIG9uIHRoZSBbUHVzaCBDaGFubmVsIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvKSBwYWdlLilcbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UuIFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLlxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCwgdGhlbiBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbiAqXG4gKiAgICAgICAgdmFyIGNzID0gbmV3IEYuc2VydmljZS5DaGFubmVsKCk7XG4gKiAgICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgU2VydmljZSBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgU2VydmljZS5cbiAqICogYG9wdGlvbnMuYmFzZWAgVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLnRvcGljUmVzb2x2ZXJgIEEgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgYWxsICd0b3BpY3MnIHBhc3NlZCBpbnRvIHRoZSBgcHVibGlzaGAgYW5kIGBzdWJzY3JpYmVgIG1ldGhvZHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGltcGxlbWVudCB5b3VyIG93biBzZXJpYWxpemUgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGN1c3RvbSBvYmplY3RzIHRvIHRvcGljIG5hbWVzLiBSZXR1cm5zIGEgU3RyaW5nLiBCeSBkZWZhdWx0LCBpdCBqdXN0IGVjaG9lcyB0aGUgdG9waWMuXG4gKiAqIGBvcHRpb25zLnRyYW5zcG9ydGAgVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLiBTZWUgaHR0cDovL2RvY3MuY29tZXRkLm9yZy9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gY29tZXRkLlxuICovXG52YXIgQ2hhbm5lbCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYmFzZSB0b3BpYy4gVGhpcyBpcyBhZGRlZCBhcyBhIHByZWZpeCB0byBhbGwgZnVydGhlciB0b3BpY3MgeW91IHB1Ymxpc2ggb3Igc3Vic2NyaWJlIHRvIHdoaWxlIHdvcmtpbmcgd2l0aCB0aGlzIENoYW5uZWwgU2VydmljZS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGJhc2U6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqIGB0b3BpY2AgVG9waWMgdG8gcGFyc2UuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiAqU3RyaW5nKjogVGhpcyBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIGEgc3RyaW5nIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICB0b3BpY1Jlc29sdmVyOiBmdW5jdGlvbiAodG9waWMpIHtcbiAgICAgICAgICAgIHJldHVybiB0b3BpYztcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiBudWxsXG4gICAgfTtcbiAgICB0aGlzLmNoYW5uZWxPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbn07XG5cbnZhciBtYWtlTmFtZSA9IGZ1bmN0aW9uIChjaGFubmVsTmFtZSwgdG9waWMpIHtcbiAgICAvL1JlcGxhY2UgdHJhaWxpbmcvZG91YmxlIHNsYXNoZXNcbiAgICB2YXIgbmV3TmFtZSA9IChjaGFubmVsTmFtZSA/IChjaGFubmVsTmFtZSArICcvJyArIHRvcGljKSA6IHRvcGljKS5yZXBsYWNlKC9cXC9cXC8vZywgJy8nKS5yZXBsYWNlKC9cXC8kLywnJyk7XG4gICAgcmV0dXJuIG5ld05hbWU7XG59O1xuXG5cbkNoYW5uZWwucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbC5wcm90b3R5cGUsIHtcblxuICAgIC8vIGZ1dHVyZSBmdW5jdGlvbmFsaXR5OlxuICAgIC8vICAgICAgLy8gU2V0IHRoZSBjb250ZXh0IGZvciB0aGUgY2FsbGJhY2tcbiAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgZnVuY3Rpb24gKCkgeyB0aGlzLmlubmVySFRNTCA9ICdUcmlnZ2VyZWQnfSwgZG9jdW1lbnQuYm9keSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gQ29udHJvbCB0aGUgb3JkZXIgb2Ygb3BlcmF0aW9ucyBieSBzZXR0aW5nIHRoZSBgcHJpb3JpdHlgXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4nLCBjYiwgdGhpcywge3ByaW9yaXR5OiA5fSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIDUwXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiA1MH0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBncmVhdGVyIHRoYW4gNTBcbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6ICc+NTAnfSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIGV2ZW5cbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6IGZ1bmN0aW9uICh2YWwpIHtyZXR1cm4gdmFsICUgMiA9PT0gMH19KTtcblxuXG4gICAgLyoqXG4gICAgICogU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqIFRoZSB0b3BpYyBzaG91bGQgaW5jbHVkZSB0aGUgZnVsbCBwYXRoIG9mIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cyksIHByb2plY3QgaWQsIGFuZCBncm91cCBuYW1lLiAoSW4gbW9zdCBjYXNlcywgaXQgaXMgc2ltcGxlciB0byB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgaW5zdGVhZCwgaW4gd2hpY2ggY2FzZSB0aGlzIGlzIGNvbmZpZ3VyZWQgZm9yIHlvdS4pXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlcyoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjYiA9IGZ1bmN0aW9uKHZhbCkgeyBjb25zb2xlLmxvZyh2YWwuZGF0YSk7IH07XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9wLWxldmVsICdydW4nIHRvcGljXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGNoaWxkcmVuIG9mIHRoZSAncnVuJyB0b3BpYy4gTm90ZSB0aGlzIHdpbGwgYWxzbyBiZSB0cmlnZ2VyZWQgZm9yIGNoYW5nZXMgdG8gcnVuLngueS56LlxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuLyonLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGJvdGggdGhlIHRvcC1sZXZlbCAncnVuJyB0b3BpYyBhbmQgaXRzIGNoaWxkcmVuXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoWycvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJyxcbiAgICAgKiAgICAgICAgICAnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJ10sIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSBwYXJ0aWN1bGFyIHZhcmlhYmxlXG4gICAgICogICAgICBzdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzL3ByaWNlJywgY2IpO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpTdHJpbmcqIFJldHVybnMgYSB0b2tlbiB5b3UgY2FuIGxhdGVyIHVzZSB0byB1bnN1YnNjcmliZS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfEFycmF5fSAgIGB0b3BpY2AgICAgTGlzdCBvZiB0b3BpY3MgdG8gbGlzdGVuIGZvciBjaGFuZ2VzIG9uLlxuICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBgY2FsbGJhY2tgIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGV4ZWN1dGUuIENhbGxiYWNrIGlzIGNhbGxlZCB3aXRoIHNpZ25hdHVyZSBgKGV2dCwgcGF5bG9hZCwgbWV0YWRhdGEpYC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgYGNvbnRleHRgICBDb250ZXh0IGluIHdoaWNoIHRoZSBgY2FsbGJhY2tgIGlzIGV4ZWN1dGVkLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gICBgb3B0aW9uc2AgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICogQHBhcmFtICB7TnVtYmVyfSAgIGBvcHRpb25zLnByaW9yaXR5YCAgVXNlZCB0byBjb250cm9sIG9yZGVyIG9mIG9wZXJhdGlvbnMuIERlZmF1bHRzIHRvIDAuIENhbiBiZSBhbnkgK3ZlIG9yIC12ZSBudW1iZXIuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE51bWJlcnxGdW5jdGlvbn0gICBgb3B0aW9ucy52YWx1ZWAgVGhlIGBjYWxsYmFja2AgaXMgb25seSB0cmlnZ2VyZWQgaWYgdGhpcyBjb25kaXRpb24gbWF0Y2hlcy4gU2VlIGV4YW1wbGVzIGZvciBkZXRhaWxzLlxuICAgICAqXG4gICAgICovXG4gICAgc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9waWMsIGNhbGxiYWNrLCBjb250ZXh0LCBvcHRpb25zKSB7XG5cbiAgICAgICAgdmFyIHRvcGljcyA9IFtdLmNvbmNhdCh0b3BpYyk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBzdWJzY3JpcHRpb25JZHMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuICAgICAgICBvcHRzLnRyYW5zcG9ydC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkLmVhY2godG9waWNzLCBmdW5jdGlvbiAoaW5kZXgsIHRvcGljKSB7XG4gICAgICAgICAgICAgICAgdG9waWMgPSBtYWtlTmFtZShvcHRzLmJhc2UsIG9wdHMudG9waWNSZXNvbHZlcih0b3BpYykpO1xuICAgICAgICAgICAgICAgIHN1YnNjcmlwdGlvbklkcy5wdXNoKG9wdHMudHJhbnNwb3J0LnN1YnNjcmliZSh0b3BpYywgY2FsbGJhY2spKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChzdWJzY3JpcHRpb25JZHNbMV0gPyBzdWJzY3JpcHRpb25JZHMgOiBzdWJzY3JpcHRpb25JZHNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBQdWJsaXNoIGRhdGEgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICAvLyBTZW5kIGRhdGEgdG8gYWxsIHN1YnNjcmliZXJzIG9mIHRoZSAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsIHsgY29tcGxldGVkOiBmYWxzZSB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bi92YXJpYWJsZXMnIHRvcGljXG4gICAgICogICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcycsIHsgcHJpY2U6IDUwIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRvcGljYCBUb3BpYyB0byBwdWJsaXNoIHRvLlxuICAgICAqIEBwYXJhbSAgeyp9IGBkYXRhYCAgRGF0YSB0byBwdWJsaXNoIHRvIHRvcGljLlxuICAgICAqXG4gICAgICovXG4gICAgcHVibGlzaDogZnVuY3Rpb24gKHRvcGljLCBkYXRhKSB7XG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgcmV0dXJuT2JqcyA9IFtdO1xuICAgICAgICB2YXIgb3B0cyA9IG1lLmNoYW5uZWxPcHRpb25zO1xuXG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBpZiAodG9waWMuY2hhckF0KHRvcGljLmxlbmd0aCAtIDEpID09PSAnKicpIHtcbiAgICAgICAgICAgICAgICAgICAgdG9waWMgPSB0b3BpYy5yZXBsYWNlKC9cXCorJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdZb3UgY2FuIGNhbm5vdCBwdWJsaXNoIHRvIGNoYW5uZWxzIHdpdGggd2lsZGNhcmRzLiBQdWJsaXNoaW5nIHRvICcsIHRvcGljLCAnaW5zdGVhZCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpzLnB1c2gob3B0cy50cmFuc3BvcnQucHVibGlzaCh0b3BpYywgZGF0YSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKHJldHVybk9ianNbMV0gPyByZXR1cm5PYmpzIDogcmV0dXJuT2Jqc1swXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVuc3Vic2NyaWJlIGZyb20gY2hhbmdlcyB0byBhIHRvcGljLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgY3MudW5zdWJzY3JpYmUoJ3NhbXBsZVRva2VuJyk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRva2VuYCBUaGUgdG9rZW4gZm9yIHRvcGljIGlzIHJldHVybmVkIHdoZW4geW91IGluaXRpYWxseSBzdWJzY3JpYmUuIFBhc3MgaXQgaGVyZSB0byB1bnN1YnNjcmliZSBmcm9tIHRoYXQgdG9waWMuXG4gICAgICovXG4gICAgdW5zdWJzY3JpYmU6IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICB0aGlzLmNoYW5uZWxPcHRpb25zLnRyYW5zcG9ydC51bnN1YnNjcmliZSh0b2tlbik7XG4gICAgICAgIHJldHVybiB0b2tlbjtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICpcbiAgICAgKiBTdXBwb3J0ZWQgZXZlbnRzIGFyZTogYGNvbm5lY3RgLCBgZGlzY29ubmVjdGAsIGBzdWJzY3JpYmVgLCBgdW5zdWJzY3JpYmVgLCBgcHVibGlzaGAsIGBlcnJvcmAuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqL1xuICAgIG9uOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vbi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdG9wIGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqL1xuICAgIG9mZjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub2ZmLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZXZlbnRzIGFuZCBleGVjdXRlIGhhbmRsZXJzLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqL1xuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENoYW5uZWw7XG4iLCIvKipcbiAqIEBjbGFzcyBDb25maWd1cmF0aW9uU2VydmljZVxuICpcbiAqIEFsbCBzZXJ2aWNlcyB0YWtlIGluIGEgY29uZmlndXJhdGlvbiBzZXR0aW5ncyBvYmplY3QgdG8gY29uZmlndXJlIHRoZW1zZWx2ZXMuIEEgSlMgaGFzaCB7fSBpcyBhIHZhbGlkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCBidXQgb3B0aW9uYWxseSB5b3UgY2FuIHVzZSB0aGUgY29uZmlndXJhdGlvbiBzZXJ2aWNlIHRvIHRvZ2dsZSBjb25maWdzIGJhc2VkIG9uIHRoZSBlbnZpcm9ubWVudFxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgdmFyIGNzID0gcmVxdWlyZSgnY29uZmlndXJhdGlvbi1zZXJ2aWNlJykoe1xuICogICAgICAgICAgZGV2OiB7IC8vZW52aXJvbm1lbnRcbiAgICAgICAgICAgICAgICBwb3J0OiAzMDAwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdsb2NhbGhvc3QnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHByb2Q6IHtcbiAgICAgICAgICAgICAgICBwb3J0OiA4MDgwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgICAgICAgICBsb2dMZXZlbDogJ25vbmUnXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbG9nTGV2ZWw6ICdERUJVRycgLy9nbG9iYWxcbiAqICAgICB9KTtcbiAqXG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudignZGV2Jyk7XG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudigncHJvZCcpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnbm9uZSdcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHVybFNlcnZpY2UgPSByZXF1aXJlKCcuL3VybC1jb25maWctc2VydmljZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IEVudmlyb25tZW50c1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgbG9nTGV2ZWw6ICdOT05FJ1xuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHNlcnZpY2VPcHRpb25zLnNlcnZlciA9IHVybFNlcnZpY2Uoc2VydmljZU9wdGlvbnMuc2VydmVyKTtcblxuICAgIHJldHVybiB7XG5cbiAgICAgICAgZGF0YTogc2VydmljZU9wdGlvbnMsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgZW52aXJvbm1lbnQga2V5IHRvIGdldCBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbVxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGVudlxuICAgICAgICAgKi9cbiAgICAgICAgc2V0RW52OiBmdW5jdGlvbiAoZW52KSB7XG5cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHByb3BlcnR5IG9wdGlvbmFsXG4gICAgICAgICAqIEByZXR1cm4geyp9ICAgICAgICAgIFZhbHVlIG9mIHByb3BlcnR5IGlmIHNwZWNpZmllZCwgdGhlIGVudGlyZSBjb25maWcgb2JqZWN0IG90aGVyd2lzZVxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9uc1twcm9wZXJ0eV07XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5IGlmIGEga2V5IGlzIHByb3ZpZGVkLCBzZXQgYSBrZXkgdG8gdGhhdCB2YWx1ZS4gT3RoZXJ3aXNlIG1lcmdlIG9iamVjdCB3aXRoIGN1cnJlbnQgY29uZmlnXG4gICAgICAgICAqIEBwYXJhbSAgeyp9IHZhbHVlICB2YWx1ZSBmb3IgcHJvdmlkZWQga2V5XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9uc1trZXldID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9O1xufTtcblxuIiwiLyoqXG4gKiAjI0RhdGEgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgRGF0YSBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgbWFuaXB1bGF0ZSBkYXRhIHJlbGF0ZWQgdG8gYW55IG9mIHlvdXIgcHJvamVjdHMuIERhdGEgYXJlIG9yZ2FuaXplZCBpbiBjb2xsZWN0aW9ucy4gRWFjaCBjb2xsZWN0aW9uIGNvbnRhaW5zIGEgZG9jdW1lbnQ7IGVhY2ggZWxlbWVudCBvZiB0aGlzIHRvcC1sZXZlbCBkb2N1bWVudCBpcyBhIEpTT04gb2JqZWN0LiAoU2VlIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gb24gdGhlIHVuZGVybHlpbmcgW0RhdGEgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvZGF0YV9hcGkvKS4pXG4gKlxuICogQWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgRGF0YSBBUEkgU2VydmljZSBkZWZhdWx0cy4gSW4gcGFydGljdWxhciwgdGhlcmUgYXJlIHRocmVlIHJlcXVpcmVkIHBhcmFtZXRlcnMgd2hlbiB5b3UgaW5zdGFudGlhdGUgdGhlIERhdGEgU2VydmljZTpcbiAqXG4gKiAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgcHJvamVjdGA6IEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICogKiBgcm9vdGA6IFRoZSB0aGUgbmFtZSBvZiB0aGUgY29sbGVjdGlvbi4gSWYgeW91IGhhdmUgbXVsdGlwbGUgY29sbGVjdGlvbnMgd2l0aGluIGVhY2ggb2YgeW91ciBwcm9qZWN0cywgeW91IGNhbiBhbHNvIHBhc3MgdGhlIGNvbGxlY3Rpb24gbmFtZSBhcyBhbiBvcHRpb24gZm9yIGVhY2ggY2FsbC5cbiAqXG4gKiAgICAgICB2YXIgZHMgPSBuZXcgRi5zZXJ2aWNlLkRhdGEoe1xuICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgIHJvb3Q6ICdzdXJ2ZXktcmVzcG9uc2VzJyxcbiAqICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBkcy5zYXZlQXMoJ3VzZXIxJyxcbiAqICAgICAgICAgIHsgJ3F1ZXN0aW9uMSc6IDIsICdxdWVzdGlvbjInOiAxMCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiBmYWxzZSwgJ3F1ZXN0aW9uNCc6ICdzb21ldGltZXMnIH0gKTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjInLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMywgJ3F1ZXN0aW9uMic6IDgsXG4gKiAgICAgICAgICAncXVlc3Rpb24zJzogdHJ1ZSwgJ3F1ZXN0aW9uNCc6ICdhbHdheXMnIH0gKTtcbiAqICAgICAgIGRzLnF1ZXJ5KCcnLHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICpcbiAqIE5vdGUgdGhhdCBpbiBhZGRpdGlvbiB0byB0aGUgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgcm9vdGAsIHRoZSBEYXRhIFNlcnZpY2UgcGFyYW1ldGVycyBvcHRpb25hbGx5IGluY2x1ZGUgYSBgc2VydmVyYCBvYmplY3QsIHdob3NlIGBob3N0YCBmaWVsZCBjb250YWlucyB0aGUgVVJJIG9mIHRoZSBGb3JpbyBzZXJ2ZXIuIFRoaXMgaXMgYXV0b21hdGljYWxseSBzZXQsIGJ1dCB5b3UgY2FuIHBhc3MgaXQgZXhwbGljaXRseSBpZiBkZXNpcmVkLiBJdCBpcyBtb3N0IGNvbW1vbmx5IHVzZWQgZm9yIGNsYXJpdHkgd2hlbiB5b3UgYXJlIFtob3N0aW5nIGFuIEVwaWNlbnRlciBwcm9qZWN0IG9uIHlvdXIgb3duIHNlcnZlcl0oLi4vLi4vLi4vaG93X3RvL3NlbGZfaG9zdGluZy8pLlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogTmFtZSBvZiBjb2xsZWN0aW9uLiBEZWZhdWx0cyB0byBgL2AsIHRoYXQgaXMsIHRoZSByb290IGxldmVsIG9mIHlvdXIgcHJvamVjdCBhdCBgZm9yaW8uY29tL2FwcC95b3VyLWFjY291bnQtaWQveW91ci1wcm9qZWN0LWlkL2AuIFJlcXVpcmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcm9vdDogJy8nLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIG9wZXJhdGlvbnMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIGRvbWFpbjogJ2ZvcmlvLmNvbScsXG5cbiAgICAgICAgLy9PcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoa2V5LCByb290KSB7XG4gICAgICAgIGlmICghcm9vdCkge1xuICAgICAgICAgICAgcm9vdCA9IHNlcnZpY2VPcHRpb25zLnJvb3Q7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdkYXRhJykgKyBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKHJvb3QpO1xuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICB1cmwrPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBUaGUgbmFtZSBvZiB0aGUgZG9jdW1lbnQgdG8gc2VhcmNoLiBQYXNzIHRoZSBlbXB0eSBzdHJpbmcgKCcnKSB0byBzZWFyY2ggdGhlIGVudGlyZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHF1ZXJ5YCBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgdG8gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHtxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBrZXlgIElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWx1ZWAgKE9wdGlvbmFsKSBUaGUgZGF0YSB0byBzYXZlLiBJZiBga2V5YCBpcyBhIHN0cmluZywgdGhpcyBpcyB0aGUgdmFsdWUgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgdmFsdWUocykgdG8gc2F2ZSBhcmUgYWxyZWFkeSBwYXJ0IG9mIGBrZXlgIGFuZCB0aGlzIGFyZ3VtZW50IGlzIG5vdCByZXF1aXJlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhIG5hbWVkIGRvY3VtZW50IG9yIGVsZW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHNlcGFyYXRlbHkgaW4gY29uZmlndXJhdGlvbiBvcHRpb25zLCBlaXRoZXIgYXMgcGFydCBvZiB0aGUgY2FsbCBvciBhcyBwYXJ0IG9mIHRoZSBpbml0aWFsaXphdGlvbiBvZiBkcy5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYGtleWAgSWQgb2YgdGhlIGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYGtleWAgVGhlIGlkIG9mIHRoZSBkYXRhIHRvIHJldHVybi4gQ2FuIGJlIHRoZSBpZCBvZiBhIGRvY3VtZW50LCBvciBhIHBhdGggdG8gZGF0YSB3aXRoaW4gdGhhdCBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChrZXksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBkYXRhIGZyb20gY29sbGVjdGlvbi4gT25seSBkb2N1bWVudHMgKHRvcC1sZXZlbCBlbGVtZW50cyBpbiBlYWNoIGNvbGxlY3Rpb24pIGNhbiBiZSBkZWxldGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgZHMucmVtb3ZlKCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xBcnJheX0gYGtleXNgIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBwYXJhbXM7XG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KGtleXMpKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBpZDoga2V5cyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSAnJztcbiAgICAgICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5cywgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFcGljZW50ZXIgZG9lc24ndCBhbGxvdyBudWtpbmcgY29sbGVjdGlvbnNcbiAgICAgICAgLy8gICAgIC8qKlxuICAgICAgICAvLyAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgLy8gICAgICAqIEByZXR1cm4gbnVsbFxuICAgICAgICAvLyAgICAgICovXG4gICAgICAgIC8vICAgICBkZXN0cm95OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgnJywgb3B0aW9ucyk7XG4gICAgICAgIC8vICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyNNZW1iZXIgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgTWVtYmVyIEFQSSBBZGFwdGVyIHByb3ZpZGVzIG1ldGhvZHMgdG8gbG9vayB1cCBpbmZvcm1hdGlvbiBhYm91dCBlbmQgdXNlcnMgZm9yIHlvdXIgcHJvamVjdCBhbmQgaG93IHRoZXkgYXJlIGRpdmlkZWQgYWNyb3NzIGdyb3Vwcy4gSXQgaXMgYmFzZWQgb24gcXVlcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW01lbWJlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvbWVtYmVyLykuXG4gKlxuICogVGhpcyBpcyBvbmx5IG5lZWRlZCBmb3IgQXV0aGVudGljYXRlZCBwcm9qZWN0cywgdGhhdCBpcywgdGVhbSBwcm9qZWN0cyB3aXRoIFtlbmQgdXNlcnMgYW5kIGdyb3Vwc10oLi4vLi4vLi4vZ3JvdXBzX2FuZF9lbmRfdXNlcnMvKS4gRm9yIGV4YW1wbGUsIGlmIHNvbWUgb2YgeW91ciBlbmQgdXNlcnMgYXJlIGZhY2lsaXRhdG9ycywgb3IgaWYgeW91ciBlbmQgdXNlcnMgc2hvdWxkIGJlIHRyZWF0ZWQgZGlmZmVyZW50bHkgYmFzZWQgb24gd2hpY2ggZ3JvdXAgdGhleSBhcmUgaW4sIHVzZSB0aGUgTWVtYmVyIEFQSSB0byBmaW5kIHRoYXQgaW5mb3JtYXRpb24uXG4gKlxuICogICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gKiAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICdiNmIzMTNhMy1hYjg0LTQ3OWMtYmFlYS0yMDZmNmJmZjMzNycgfSk7XG4gKiAgICAgIG1hLmdldEdyb3VwRGV0YWlscyh7IGdyb3VwSWQ6ICcwMGI1MzMwOC05ODMzLTQ3ZjItYjIxZS0xMjc4YzA3ZDUzYjgnIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGFwaUVuZHBvaW50ID0gJ21lbWJlci9sb2NhbCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciB1c2VyIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBncm91cCBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuIE5vdGUgdGhhdCB0aGlzIGlzIHRoZSBncm91cCAqaWQqLCBub3QgdGhlIGdyb3VwICpuYW1lKi5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGdyb3VwSWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucywgc2VydmljZU9wdGlvbnMpO1xuXG4gICAgdmFyIGdldEZpbmFsUGFyYW1zID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBwYXRjaFVzZXJBY3RpdmVGaWVsZCA9IGZ1bmN0aW9uIChwYXJhbXMsIGFjdGl2ZSwgb3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBwYXJhbXMuZ3JvdXBJZCArICcvJyArIHBhcmFtcy51c2VySWRcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goeyBhY3RpdmU6IGFjdGl2ZSB9LCBodHRwT3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBhbGwgb2YgdGhlIGdyb3VwIG1lbWJlcnNoaXBzIGZvciBvbmUgZW5kIHVzZXIuIFRoZSBtZW1iZXJzaGlwIGRldGFpbHMgYXJlIHJldHVybmVkIGluIGFuIGFycmF5LCB3aXRoIG9uZSBlbGVtZW50IChncm91cCByZWNvcmQpIGZvciBlYWNoIGdyb3VwIHRvIHdoaWNoIHRoZSBlbmQgdXNlciBiZWxvbmdzLlxuICAgICAgICAqXG4gICAgICAgICogSW4gdGhlIG1lbWJlcnNoaXAgYXJyYXksIGVhY2ggZ3JvdXAgcmVjb3JkIGluY2x1ZGVzIHRoZSBncm91cCBpZCwgcHJvamVjdCBpZCwgYWNjb3VudCAodGVhbSkgaWQsIGFuZCBhbiBhcnJheSBvZiBtZW1iZXJzLiBIb3dldmVyLCBvbmx5IHRoZSB1c2VyIHdob3NlIHVzZXJJZCBpcyBpbmNsdWRlZCBpbiB0aGUgY2FsbCBpcyBsaXN0ZWQgaW4gdGhlIG1lbWJlcnMgYXJyYXkgKHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGVyZSBhcmUgb3RoZXIgbWVtYmVycyBpbiB0aGlzIGdyb3VwKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcignNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24obWVtYmVyc2hpcHMpe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPG1lbWJlcnNoaXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cobWVtYmVyc2hpcHNbaV0uZ3JvdXBJZCk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gYHBhcmFtc2AgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlci4gQWx0ZXJuYXRpdmVseSwgYW4gb2JqZWN0IHdpdGggZmllbGQgYHVzZXJJZGAgYW5kIHZhbHVlIHRoZSB1c2VyIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRHcm91cHNGb3JVc2VyOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB1c2VySWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ2V0UGFybXMgPSBpc1N0cmluZyA/IHsgdXNlcklkOiBwYXJhbXMgfSA6IF9waWNrKG9ialBhcmFtcywgJ3VzZXJJZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldFBhcm1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBvbmUgZ3JvdXAsIGluY2x1ZGluZyBhbiBhcnJheSBvZiBhbGwgaXRzIG1lbWJlcnMuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3VwRGV0YWlscygnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZ3JvdXApe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPGdyb3VwLm1lbWJlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhncm91cC5tZW1iZXJzW2ldLnVzZXJOYW1lKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIH1cbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoeyBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fSBgcGFyYW1zYCBUaGUgZ3JvdXAgaWQuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGBncm91cElkYCBhbmQgdmFsdWUgdGhlIGdyb3VwIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0R3JvdXBEZXRhaWxzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMuZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZ3JvdXBJZCBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBncm91cElkID0gaXNTdHJpbmcgPyBwYXJhbXMgOiBvYmpQYXJhbXMuZ3JvdXBJZDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIGdyb3VwSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgYWN0aXZlYC4gQWN0aXZlIGVuZCB1c2VycyBjYW4gYmUgYXNzaWduZWQgdG8gW3dvcmxkc10oLi4vd29ybGQtbWFuYWdlci8pIGluIG11bHRpcGxheWVyIGdhbWVzIGR1cmluZyBhdXRvbWF0aWMgYXNzaWdubWVudC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEubWFrZVVzZXJBY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIG1ha2VVc2VyQWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCB0cnVlLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBTZXQgYSBwYXJ0aWN1bGFyIGVuZCB1c2VyIGFzIGBpbmFjdGl2ZWAuIEluYWN0aXZlIGVuZCB1c2VycyBhcmUgbm90IGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VySW5hY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggdGhpcyBlbmQgdXNlciBiZWxvbmdzLCBhbmQgaW4gd2hpY2ggdGhlIGVuZCB1c2VyIHNob3VsZCBiZWNvbWUgaW5hY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckluYWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCBmYWxzZSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI1J1biBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBSdW4gQVBJIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBwZXJmb3JtIGNvbW1vbiB0YXNrcyBhcm91bmQgY3JlYXRpbmcgYW5kIHVwZGF0aW5nIHJ1bnMsIHZhcmlhYmxlcywgYW5kIGRhdGEuXG4gKlxuICogV2hlbiBidWlsZGluZyBpbnRlcmZhY2VzIHRvIHNob3cgcnVuIG9uZSBhdCBhIHRpbWUgKGFzIGZvciBzdGFuZGFyZCBlbmQgdXNlcnMpLCB0eXBpY2FsbHkgeW91IGZpcnN0IGluc3RhbnRpYXRlIGEgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGFuZCB0aGVuIGFjY2VzcyB0aGUgUnVuIFNlcnZpY2UgdGhhdCBpcyBhdXRvbWF0aWNhbGx5IHBhcnQgb2YgdGhlIG1hbmFnZXIsIHJhdGhlciB0aGFuIGluc3RhbnRpYXRpbmcgdGhlIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LiBUaGlzIGlzIGJlY2F1c2UgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLlxuICpcbiAqIEhvd2V2ZXIsIG1hbnkgb2YgdGhlIEVwaWNlbnRlciBzYW1wbGUgcHJvamVjdHMgdXNlIGEgUnVuIFNlcnZpY2UsIGJlY2F1c2UgZ2VuZXJhbGx5IHRoZSBzYW1wbGUgcHJvamVjdHMgYXJlIHBsYXllZCBpbiBvbmUgZW5kIHVzZXIgc2Vzc2lvbiBhbmQgZG9uJ3QgY2FyZSBhYm91dCBydW4gc3RhdGVzIG9yIFtydW4gc3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKS4gVGhlIFJ1biBBUEkgU2VydmljZSBpcyBhbHNvIHVzZWZ1bCBmb3IgYnVpbGRpbmcgYW4gaW50ZXJmYWNlIGZvciBhIGZhY2lsaXRhdG9yLCBiZWNhdXNlIGl0IG1ha2VzIGl0IGVhc3kgdG8gbGlzdCBkYXRhIGFjcm9zcyBtdWx0aXBsZSBydW5zICh1c2luZyB0aGUgYGZpbHRlcigpYCBhbmQgYHF1ZXJ5KClgIG1ldGhvZHMpLlxuICpcbiAqIFRvIHVzZSB0aGUgUnVuIEFQSSBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKlxuICogRm9yIGV4YW1wbGUsXG4gKlxuICogICAgICAgdmFyIHJzID0gbmV3IEYuc2VydmljZS5SdW4oe1xuICogICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgIH0pO1xuICogICAgICBycy5jcmVhdGUoJ3N1cHBseV9jaGFpbl9nYW1lLnB5JykudGhlbihmdW5jdGlvbihydW4pIHtcbiAqICAgICAgICAgICAgIHJzLmRvKCdzb21lT3BlcmF0aW9uJyk7XG4gKiAgICAgIH0pO1xuICpcbiAqXG4gKiBBZGRpdGlvbmFsbHksIGFsbCBBUEkgY2FsbHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFJ1biBBUEkgU2VydmljZSBkZWZhdWx0cyBsaXN0ZWQgYmVsb3cuXG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGBtb2RlbGAsIHRoZSBSdW4gU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKlxuICogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiAqICAgICAgICAgICBydW46IHtcbiAqICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseV9jaGFpbl9nYW1lLnB5JyxcbiAqICAgICAgICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICAgICAgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBybS5nZXRSdW4oKVxuICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBSdW4gU2VydmljZSxcbiAqICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4gKiAgICAgICAgICAgICAgIHZhciBycyA9IHJtLnJ1bjtcbiAqICAgICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgIH0pXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgVmFyaWFibGVzU2VydmljZSA9IHJlcXVpcmUoJy4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8IHN0b3JlLmdldCgnZXBpY2VudGVyLnRva2VuJykgfHwgJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgcnVucy4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlci5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRmxhZyBkZXRlcm1pbmVzIGlmIGBYLUF1dG9SZXN0b3JlOiB0cnVlYCBoZWFkZXIgaXMgc2VudCB0byBFcGljZW50ZXIuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBhdXRvUmVzdG9yZTogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuICAgIHVybENvbmZpZy5nZXRGaWx0ZXJVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJyk7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBxdXRpbC50b01hdHJpeEZvcm1hdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpO1xuXG4gICAgICAgIGlmIChmaWx0ZXIpIHtcbiAgICAgICAgICAgIHVybCArPSBmaWx0ZXIgKyAnLyc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmZpbHRlcjtcbiAgICAgICAgLy8gVGhlIHNlbWljb2xvbiBzZXBhcmF0ZWQgZmlsdGVyIGlzIHVzZWQgd2hlbiBmaWx0ZXIgaXMgYW4gb2JqZWN0XG4gICAgICAgIHZhciBpc0ZpbHRlclJ1bklkID0gZmlsdGVyICYmICQudHlwZShmaWx0ZXIpID09PSAnc3RyaW5nJztcbiAgICAgICAgaWYgKHNlcnZpY2VPcHRpb25zLmF1dG9SZXN0b3JlICYmIGlzRmlsdGVyUnVuSWQpIHtcbiAgICAgICAgICAgIC8vIEJ5IGRlZmF1bHQgYXV0b3JlcGxheSB0aGUgcnVuIGJ5IHNlbmRpbmcgdGhpcyBoZWFkZXIgdG8gZXBpY2VudGVyXG4gICAgICAgICAgICAvLyBodHRwczovL2ZvcmlvLmNvbS9lcGljZW50ZXIvZG9jcy9wdWJsaWMvcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNyZXRyaWV2aW5nXG4gICAgICAgICAgICB2YXIgYXV0b3Jlc3RvcmVPcHRzID0ge1xuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJ1gtQXV0b1Jlc3RvcmUnOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBhdXRvcmVzdG9yZU9wdHMsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgc2V0RmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBmaWx0ZXIgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgdXJsQ29uZmlnOiB1cmxDb25maWcsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyZWF0ZSBhIG5ldyBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIE5PVEU6IFR5cGljYWxseSB0aGlzIGlzIG5vdCB1c2VkISBVc2UgYFJ1bk1hbmFnZXIuZ2V0UnVuKClgIHdpdGggYSBgc3RyYXRlZ3lgIG9mIGBhbHdheXMtbmV3YCwgb3IgdXNlIGBSdW5NYW5hZ2VyLnJlc2V0KClgLiBTZWUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHJzLmNyZWF0ZSgnaGVsbG9fd29ybGQuamwnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYHBhcmFtc2AgSWYgYSBzdHJpbmcsIHRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IFttb2RlbCBmaWxlXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4gVGhpcyBpcyB0aGUgb25lIGZpbGUgaW4gdGhlIHByb2plY3QgdGhhdCBleHBsaWNpdGx5IGV4cG9zZXMgdmFyaWFibGVzIGFuZCBtZXRob2RzLCBhbmQgaXQgbXVzdCBiZSBzdG9yZWQgaW4gdGhlIE1vZGVsIGZvbGRlciBvZiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBJZiBhbiBvYmplY3QsIG1heSBpbmNsdWRlIGBtb2RlbGAsIGBzY29wZWAsIGFuZCBgZmlsZXNgLiAoU2VlIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bl9tYW5hZ2VyLykgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gYHNjb3BlYCBhbmQgYGZpbGVzYC4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICpcbiAgICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJykgfSk7XG4gICAgICAgICAgICB2YXIgcnVuQXBpUGFyYW1zID0gWydtb2RlbCcsICdzY29wZScsICdmaWxlcyddO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gdGhpcyBpcyBqdXN0IHRoZSBtb2RlbCBuYW1lXG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBtb2RlbDogcGFyYW1zIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHdoaXRlbGlzdCB0aGUgZmllbGRzIHRoYXQgd2UgYWN0dWFsbHkgY2FuIHNlbmQgdG8gdGhlIGFwaVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgcnVuQXBpUGFyYW1zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGVsZW1lbnRzIG9mIHRoZSBgcXNgIG9iamVjdCBhcmUgQU5EZWQgdG9nZXRoZXIgd2l0aGluIGEgc2luZ2xlIGNhbGwgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZXR1cm5zIHJ1bnMgd2l0aCBzYXZlZCA9IHRydWUgYW5kIHZhcmlhYmxlcy5wcmljZSA+IDEsXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgdmFyaWFibGVzLnByaWNlIGhhcyBiZWVuIHBlcnNpc3RlZCAocmVjb3JkZWQpXG4gICAgICAgICAqICAgICAgLy8gaW4gdGhlIG1vZGVsLlxuICAgICAgICAgKiAgICAgcnMucXVlcnkoe1xuICAgICAgICAgKiAgICAgICAgICAnc2F2ZWQnOiAndHJ1ZScsXG4gICAgICAgICAqICAgICAgICAgICcucHJpY2UnOiAnPjEnXG4gICAgICAgICAqICAgICAgIH0sXG4gICAgICAgICAqICAgICAgIHtcbiAgICAgICAgICogICAgICAgICAgc3RhcnRyZWNvcmQ6IDIsXG4gICAgICAgICAqICAgICAgICAgIGVuZHJlY29yZDogNVxuICAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBxc2AgUXVlcnkgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBRdWVyeWluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXMsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBxczsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFNpbWlsYXIgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJgIEZpbHRlciBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIEZpbHRlcmluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogZnVuY3Rpb24gKGZpbHRlciwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qoc2VydmljZU9wdGlvbnMuZmlsdGVyKSkge1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlcnZpY2VPcHRpb25zLmZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gZmlsdGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBkYXRhIGZvciBhIHNwZWNpZmljIHJ1bi4gVGhpcyBpbmNsdWRlcyBzdGFuZGFyZCBydW4gZGF0YSBzdWNoIGFzIHRoZSBhY2NvdW50LCBtb2RlbCwgcHJvamVjdCwgYW5kIGNyZWF0ZWQgYW5kIGxhc3QgbW9kaWZpZWQgZGF0ZXMuIFRvIHJlcXVlc3Qgc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLCBwYXNzIHRoZW0gYXMgcGFydCBvZiB0aGUgYGZpbHRlcnNgIHBhcmFtZXRlci5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IGlmIHRoZSBydW4gaXMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSksIGFueSBtb2RlbCB2YXJpYWJsZXMgYXJlIGF2YWlsYWJsZTsgaWYgdGhlIHJ1biBpcyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLCBvbmx5IG1vZGVsIHZhcmlhYmxlcyB0aGF0IGhhdmUgYmVlbiBwZXJzaXN0ZWQgJm1kYXNoOyB0aGF0IGlzLCBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwgJm1kYXNoOyBhcmUgYXZhaWxhYmxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgcnMubG9hZCgnYmI1ODk2NzctZDQ3Ni00OTcxLWE2OGUtMGM1OGQxOTFlNDUwJywgeyBpbmNsdWRlOiBbJy5wcmljZScsICcuc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBydW5JRGAgVGhlIHJ1biBpZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJzYCAoT3B0aW9uYWwpIE9iamVjdCBjb250YWluaW5nIGZpbHRlcnMgYW5kIG9wZXJhdGlvbiBtb2RpZmllcnMuIFVzZSBrZXkgYGluY2x1ZGVgIHRvIGxpc3QgbW9kZWwgdmFyaWFibGVzIHRoYXQgeW91IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUgcmVzcG9uc2UuIE90aGVyIGF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAocnVuSUQsIGZpbHRlcnMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmIChydW5JRCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJ1bklEOyAvL3Nob3VsZG4ndCBiZSBhYmxlIHRvIG92ZXItcmlkZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBhdHRyaWJ1dGVzIChkYXRhLCBtb2RlbCB2YXJpYWJsZXMpIG9mIHRoZSBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gYWRkICdjb21wbGV0ZWQnIGZpZWxkIHRvIHJ1biByZWNvcmRcbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBjb21wbGV0ZWQ6IHRydWUgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyB1cGRhdGUgJ3NhdmVkJyBmaWVsZCBvZiBydW4gcmVjb3JkLCBhbmQgdXBkYXRlIHZhbHVlcyBvZiBtb2RlbCB2YXJpYWJsZXMgZm9yIHRoaXMgcnVuXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgc2F2ZWQ6IHRydWUsIHZhcmlhYmxlczogeyBhOiAyMywgYjogMjMgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBhdHRyaWJ1dGVzYCBUaGUgcnVuIGRhdGEgYW5kIHZhcmlhYmxlcyB0byBzYXZlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGF0dHJpYnV0ZXMudmFyaWFibGVzYCBNb2RlbCB2YXJpYWJsZXMgbXVzdCBiZSBpbmNsdWRlZCBpbiBhIGB2YXJpYWJsZXNgIGZpZWxkIHdpdGhpbiB0aGUgYGF0dHJpYnV0ZXNgIG9iamVjdC4gKE90aGVyd2lzZSB0aGV5IGFyZSB0cmVhdGVkIGFzIHJ1biBkYXRhIGFuZCBhZGRlZCB0byB0aGUgcnVuIHJlY29yZCBkaXJlY3RseS4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uIChhdHRyaWJ1dGVzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKGF0dHJpYnV0ZXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBhIG1ldGhvZCBmcm9tIHRoZSBtb2RlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2QgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGBwYXJhbXNgIGFyZ3VtZW50IGlzIG5vcm1hbGx5IGFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byB0aGUgYG9wZXJhdGlvbmAuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXkuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCB5b3UgY2FuIGNvbWJpbmUgdGhlIGBvcGVyYXRpb25gIGFuZCBgcGFyYW1zYCBhcmd1bWVudHMgaW50byBhIHNpbmdsZSBvYmplY3QgaWYgeW91IHByZWZlciwgYXMgaW4gdGhlIGxhc3QgZXhhbXBsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic29sdmVcIiB0YWtlcyBubyBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLmRvKCdzb2x2ZScpO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsIFsnaGVsbG8nXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgJ2hlbGxvJyk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic3VtQXJyYXlcIiB0YWtlcyBvbmUgYXJndW1lbnQsIGFuIGFycmF5XG4gICAgICAgICAqICAgICBycy5kbygnc3VtQXJyYXknLCBbWzQsMiwxXV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImFkZFwiIHRha2VzIHR3byBhcmd1bWVudHMsIGJvdGggaW50ZWdlcnNcbiAgICAgICAgICogICAgIHJzLmRvKHsgbmFtZTonYWRkJywgcGFyYW1zOlsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYG9wZXJhdGlvbmAgTmFtZSBvZiBtZXRob2QuXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBwYXJhbXNgIChPcHRpb25hbCkgQW55IHBhcmFtZXRlcnMgdGhlIG9wZXJhdGlvbiB0YWtlcywgcGFzc2VkIGFzIGFuIGFycmF5LiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LCBhbmQgY2FuIGp1c3QgcGFzcyBpdCBkaXJlY3RseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZG86IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ2RvJywgb3BlcmF0aW9uLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wc0FyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnM7XG4gICAgICAgICAgICBpZiAob3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICAgICAgb3BzQXJncyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9uLCBvcHNBcmdzKTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgcG9zdE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcHJtcyA9IChyZXN1bHQuYXJnc1swXS5sZW5ndGggJiYgKHJlc3VsdC5hcmdzWzBdICE9PSBudWxsICYmIHJlc3VsdC5hcmdzWzBdICE9PSB1bmRlZmluZWQpKSA/IHJlc3VsdC5hcmdzWzBdIDogW107XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgYXJndW1lbnRzOiBwcm1zIH0sICQuZXh0ZW5kKHRydWUsIHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ29wZXJhdGlvbnMvJyArIHJlc3VsdC5vcHNbMF0gKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwsIHNlcXVlbnRpYWxseS5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2RzIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0aWFsaXplXCIgYW5kIFwic29sdmVcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWydpbml0aWFsaXplJywgJ3NvbHZlJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0XCIgYW5kIFwicmVzZXRcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncmVzZXQnLCBwYXJhbXM6IFsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJpbml0XCIgdGFrZXMgdHdvIGFyZ3VtZW50cyxcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJydW5tb2RlbFwiIHRha2VzIG5vbmVcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3J1bm1vZGVsJywgcGFyYW1zOiBbXSB9XSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBvcGVyYXRpb25zYCBJZiBub25lIG9mIHRoZSBtZXRob2RzIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgbWV0aG9kIG5hbWVzIChzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBtZXRob2RzIGRvIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGEgbWV0aG9kIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzZXJpYWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9TaW5nbGVPcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgb3AgPSBvcHMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICB2YXIgYXJnID0gYXJncy5zaGlmdCgpO1xuXG4gICAgICAgICAgICAgICAgbWUuZG8ob3AsIGFyZywge1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob3BzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbCwgZXhlY3V0aW5nIHRoZW0gaW4gcGFyYWxsZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kcyBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJzb2x2ZVwiIGFuZCBcInJlc2V0XCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWydzb2x2ZScsICdyZXNldCddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWyB7IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3N1YnRyYWN0JywgcGFyYW1zOlsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoeyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fSBgb3BlcmF0aW9uc2AgSWYgbm9uZSBvZiB0aGUgbWV0aG9kcyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG1ldGhvZCBuYW1lcyAoYXMgc3RyaW5ncykuIElmIGFueSBvZiB0aGUgbWV0aG9kcyBkbyB0YWtlIHBhcmFtZXRlcnMsIHlvdSBoYXZlIHR3byBvcHRpb25zLiBZb3UgY2FuIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhIG1ldGhvZCBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBwYXNzIGEgc2luZ2xlIG9iamVjdCB3aXRoIHRoZSBtZXRob2QgbmFtZSBhbmQgYSAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFsbGVsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG5cbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcXVldWUgID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaTwgb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcXVldWUucHVzaChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kbyhvcHNbaV0sIGFyZ3NbaV0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICQud2hlbi5hcHBseSh0aGlzLCBxdWV1ZSlcbiAgICAgICAgICAgICAgICAuZG9uZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2Vzcy5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvci5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY1N5bmNBUEkgPSB7XG4gICAgICAgIGdldEN1cnJlbnRDb25maWc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgfSxcbiAgICAgICAgLyoqXG4gICAgICAgICAgKiBSZXR1cm5zIGEgVmFyaWFibGVzIFNlcnZpY2UgaW5zdGFuY2UuIFVzZSB0aGUgdmFyaWFibGVzIGluc3RhbmNlIHRvIGxvYWQsIHNhdmUsIGFuZCBxdWVyeSBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLiBTZWUgdGhlIFtWYXJpYWJsZSBBUEkgU2VydmljZV0oLi4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAgICAgICAgKlxuICAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAgICAgIHZhciB2cyA9IHJzLnZhcmlhYmxlcygpO1xuICAgICAgICAgICogICAgICB2cy5zYXZlKHsgc2FtcGxlX2ludDogNCB9KTtcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBjb25maWdgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAgKi9cbiAgICAgICAgdmFyaWFibGVzOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgdnMgPSBuZXcgVmFyaWFibGVzU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZywge1xuICAgICAgICAgICAgICAgIHJ1blNlcnZpY2U6IHRoaXNcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIHJldHVybiB2cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljU3luY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4gKiAjI1N0YXRlIEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIFN0YXRlIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gcmVwbGF5IG9yIGNsb25lIHJ1bnMuIEl0IGJyaW5ncyBleGlzdGluZywgcGVyc2lzdGVkIHJ1biBkYXRhIGZyb20gdGhlIGRhdGFiYXNlIGJhY2sgaW50byBtZW1vcnksIHVzaW5nIHRoZSBzYW1lIHJ1biBpZCAoYHJlcGxheWApIG9yIGEgbmV3IHJ1biBpZCAoYGNsb25lYCkuIFJ1bnMgbXVzdCBiZSBpbiBtZW1vcnkgaW4gb3JkZXIgZm9yIHlvdSB0byB1cGRhdGUgdmFyaWFibGVzIG9yIGNhbGwgb3BlcmF0aW9ucyBvbiB0aGVtLlxuICpcbiAqIFNwZWNpZmljYWxseSwgdGhlIFN0YXRlIEFQSSBBZGFwdGVyIHdvcmtzIGJ5IFwicmUtcnVubmluZ1wiIHRoZSBydW4gKHVzZXIgaW50ZXJhY3Rpb25zKSBmcm9tIHRoZSBjcmVhdGlvbiBvZiB0aGUgcnVuIHVwIHRvIHRoZSB0aW1lIGl0IHdhcyBsYXN0IHBlcnNpc3RlZCBpbiB0aGUgZGF0YWJhc2UuIFRoaXMgcHJvY2VzcyB1c2VzIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIHJ1bidzIG1vZGVsLiBUaGVyZWZvcmUsIGlmIHRoZSBtb2RlbCBoYXMgY2hhbmdlZCBzaW5jZSB0aGUgb3JpZ2luYWwgcnVuIHdhcyBjcmVhdGVkLCB0aGUgcmV0cmlldmVkIHJ1biB3aWxsIHVzZSB0aGUgbmV3IG1vZGVsIOKAlCBhbmQgbWF5IGVuZCB1cCBoYXZpbmcgZGlmZmVyZW50IHZhbHVlcyBvciBiZWhhdmlvciBhcyBhIHJlc3VsdC4gVXNlIHdpdGggY2FyZSFcbiAqXG4gKiBUbyB1c2UgdGhlIFN0YXRlIEFQSSBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBjYWxsIGl0cyBtZXRob2RzOlxuICpcbiAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJ30pO1xuICpcbiAqIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgcHJvamVjdGAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4gKlxuICovXG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBhcGlFbmRwb2ludCA9ICdtb2RlbC9zdGF0ZSc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgfTtcblxuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcbiAgICB2YXIgcGFyc2VSdW5JZE9yRXJyb3IgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSAmJiBwYXJhbXMucnVuSWQpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbXMucnVuSWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwYXNzIGluIGEgcnVuIGlkJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGF5IGEgcnVuLiBBZnRlciB0aGlzIGNhbGwsIHRoZSBydW4sIHdpdGggaXRzIG9yaWdpbmFsIHJ1biBpZCwgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gKEl0IGNvbnRpbnVlcyB0byBiZSBwZXJzaXN0ZWQgaW50byB0aGUgRXBpY2VudGVyIGRhdGFiYXNlIGF0IHJlZ3VsYXIgaW50ZXJ2YWxzLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJywgc3RvcEJlZm9yZTogJ2NhbGN1bGF0ZVNjb3JlJ30pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBicmluZyBiYWNrIHRvIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBgcGFyYW1zLmV4Y2x1ZGVgIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZXBsYXk6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdyZXBsYXknIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ2xvbmUgYSBnaXZlbiBydW4gYW5kIHJldHVybiBhIG5ldyBydW4gaW4gdGhlIHNhbWUgc3RhdGUgYXMgdGhlIGdpdmVuIHJ1bi5cbiAgICAgICAgKlxuICAgICAgICAqIFRoZSBuZXcgcnVuIGlkIGlzIG5vdyBhdmFpbGFibGUgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIFRoZSBuZXcgcnVuIGluY2x1ZGVzIGEgY29weSBvZiBhbGwgb2YgdGhlIGRhdGEgZnJvbSB0aGUgb3JpZ2luYWwgcnVuLCBFWENFUFQ6XG4gICAgICAgICpcbiAgICAgICAgKiAqIFRoZSBgc2F2ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAuXG4gICAgICAgICogKiBUaGUgYGluaXRpYWxpemVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgbm90IGNvcGllZCBmcm9tIHRoZSBvcmlnaW5hbCBydW4gcmVjb3JkLiBJdCBkZWZhdWx0cyB0byBgZmFsc2VgIGJ1dCBtYXkgY2hhbmdlIHRvIGB0cnVlYCBhcyB0aGUgbmV3IHJ1biBpcyBhZHZhbmNlZC4gRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGhhcyBiZWVuIGEgY2FsbCB0byB0aGUgYHN0ZXBgIGZ1bmN0aW9uIChmb3IgVmVuc2ltIG1vZGVscyksIHRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGlzIHNldCB0byBgdHJ1ZWAuXG4gICAgICAgICogKiBUaGUgYGNyZWF0ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyB0aGUgZGF0ZSBhbmQgdGltZSBhdCB3aGljaCB0aGUgY2xvbmUgd2FzIGNyZWF0ZWQgKG5vdCB0aGUgdGltZSB0aGF0IHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQuKVxuICAgICAgICAqXG4gICAgICAgICogVGhlIG9yaWdpbmFsIHJ1biByZW1haW5zIG9ubHkgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLWRiKS5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5jbG9uZSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnLCBleGNsdWRlOiBbJ2ludGVyaW1DYWxjdWxhdGlvbiddIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBjbG9uZSBmcm9tIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBuZXdseSBjbG9uZWQgcnVuIGlzIGFkdmFuY2VkIG9ubHkgdXAgdG8gdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgdGhpcyBtZXRob2QuXG4gICAgICAgICogQHBhcmFtIHthcnJheX0gYHBhcmFtcy5leGNsdWRlYCAoT3B0aW9uYWwpIEFycmF5IG9mIG1ldGhvZHMgdG8gZXhjbHVkZSB3aGVuIGFkdmFuY2luZyB0aGUgbmV3bHkgY2xvbmVkIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGNsb25lOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcnVuSWQgPSBwYXJzZVJ1bklkT3JFcnJvcihwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgcmVwbGF5T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHJ1bklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgYWN0aW9uOiAnY2xvbmUnIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBlcGlWZXJzaW9uID0gcmVxdWlyZSgnLi4vYXBpLXZlcnNpb24uanNvbicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IHVybHV0aWxzIHRvIGdldCBob3N0LCBzaW5jZSBubyB3aW5kb3cgb24gbm9kZVxuXG4gICAgdmFyIEFQSV9QUk9UT0NPTCA9ICdodHRwcyc7XG4gICAgdmFyIEhPU1RfQVBJX01BUFBJTkcgPSB7XG4gICAgICAgICdmb3Jpby5jb20nOiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICdmb3Jpb2Rldi5jb20nOiAnYXBpLmVwaWNlbnRlci5mb3Jpb2Rldi5jb20nXG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNFeHBvcnRzID0ge1xuICAgICAgICBwcm90b2NvbDogQVBJX1BST1RPQ09MLFxuXG4gICAgICAgIGFwaTogJycsXG5cbiAgICAgICAgaG9zdDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICBpZiAoIWhvc3QgfHwgaG9zdC5pbmRleE9mKCdsb2NhbCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGhvc3QgPSAnZm9yaW8uY29tJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAoSE9TVF9BUElfTUFQUElOR1tob3N0XSkgPyBIT1NUX0FQSV9NQVBQSU5HW2hvc3RdIDogJ2FwaS4nICsgaG9zdDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBhcHBQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gcGF0aCAmJiBwYXRoWzFdIHx8ICcnO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFjY291bnRQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFjY250ID0gJyc7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIGFjY250ID0gcGF0aFsyXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhY2NudDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBwcm9qZWN0UGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwcmogPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIGlmIChwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnKSB7XG4gICAgICAgICAgICAgICAgcHJqID0gcGF0aFszXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBwcmo7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgdmVyc2lvblBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgdmVyc2lvbiA9IGVwaVZlcnNpb24udmVyc2lvbiA/IGVwaVZlcnNpb24udmVyc2lvbiArICcvJyA6ICcnO1xuICAgICAgICAgICAgcmV0dXJuIHZlcnNpb247XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgaXNMb2NhbGhvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICByZXR1cm4gKCFob3N0IHx8IGhvc3QuaW5kZXhPZignbG9jYWwnKSAhPT0gLTEpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGdldEFQSVBhdGg6IGZ1bmN0aW9uIChhcGkpIHtcbiAgICAgICAgICAgIHZhciBQUk9KRUNUX0FQSVMgPSBbJ3J1bicsICdkYXRhJywgJ2ZpbGUnXTtcblxuICAgICAgICAgICAgdmFyIGFwaVBhdGggPSB0aGlzLnByb3RvY29sICsgJzovLycgKyB0aGlzLmhvc3QgKyAnLycgKyB0aGlzLnZlcnNpb25QYXRoICsgYXBpICsgJy8nO1xuXG4gICAgICAgICAgICBpZiAoJC5pbkFycmF5KGFwaSwgUFJPSkVDVF9BUElTKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBhcGlQYXRoICs9IHRoaXMuYWNjb3VudFBhdGggKyAnLycgKyB0aGlzLnByb2plY3RQYXRoICArICcvJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhcGlQYXRoO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHB1YmxpY0V4cG9ydHMsIGNvbmZpZyk7XG4gICAgcmV0dXJuIHB1YmxpY0V4cG9ydHM7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4qICMjVXNlciBBUEkgQWRhcHRlclxuKlxuKiBUaGUgVXNlciBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHJldHJpZXZlIGRldGFpbHMgYWJvdXQgZW5kIHVzZXJzIGluIHlvdXIgdGVhbSAoYWNjb3VudCkuIEl0IGlzIGJhc2VkIG9uIHRoZSBxdWVyeWluZyBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbVXNlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvdXNlci8pLlxuKlxuKiBUbyB1c2UgdGhlIFVzZXIgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHMuXG4qXG4qICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nXG4qICAgICAgIH0pO1xuKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiogICAgICAgdWEuZ2V0KHsgdXNlck5hbWU6ICdqc21pdGgnIH0pO1xuKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4qXG4qIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgdG9rZW5gIGlmIHRoZXkgYXJlIG5vdCBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgY3VycmVudCBjb250ZXh0LlxuKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2Nlc3MgdG9rZW4gdG8gdXNlIHdoZW4gc2VhcmNoaW5nIGZvciBlbmQgdXNlcnMuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgcGFydGljdWxhciBlbmQgdXNlcnMgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIG5hbWUgb3IgdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4gICAgICAgICogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgZmlsdGVyYCBPYmplY3Qgd2l0aCBmaWVsZCBgdXNlck5hbWVgIGFuZCB2YWx1ZSBvZiB0aGUgdXNlcm5hbWUuIEFsdGVybmF0aXZlbHksIG9iamVjdCB3aXRoIGZpZWxkIGBpZGAgYW5kIHZhbHVlIG9mIGFuIGFycmF5IG9mIHVzZXIgaWRzLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWx0ZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciB0b1FGaWx0ZXIgPSBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgLy8gQVBJIG9ubHkgc3VwcG9ydHMgZmlsdGVyaW5nIGJ5IHVzZXJuYW1lIGZvciBub3dcbiAgICAgICAgICAgICAgICBpZiAoZmlsdGVyLnVzZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5xID0gZmlsdGVyLnVzZXJOYW1lO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgdG9JZEZpbHRlcnMgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZCA9ICQuaXNBcnJheShpZCkgPyBpZCA6IFtpZF07XG4gICAgICAgICAgICAgICAgcmV0dXJuICdpZD0nICsgaWQuam9pbignJmlkPScpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIGdldEZpbHRlcnMgPSBbXG4gICAgICAgICAgICAgICAgJ2FjY291bnQ9JyArIGdldE9wdGlvbnMuYWNjb3VudCxcbiAgICAgICAgICAgICAgICB0b0lkRmlsdGVycyhmaWx0ZXIuaWQpLFxuICAgICAgICAgICAgICAgIHF1dGlsLnRvUXVlcnlGb3JtYXQodG9RRmlsdGVyKGZpbHRlcikpXG4gICAgICAgICAgICBdLmpvaW4oJyYnKTtcblxuICAgICAgICAgICAgLy8gc3BlY2lhbCBjYXNlIGZvciBxdWVyaWVzIHdpdGggbGFyZ2UgbnVtYmVyIG9mIGlkc1xuICAgICAgICAgICAgLy8gbWFrZSBpdCBhcyBhIHBvc3Qgd2l0aCBHRVQgc2VtYW50aWNzXG4gICAgICAgICAgICB2YXIgdGhyZXNob2xkID0gMzA7XG4gICAgICAgICAgICBpZiAoZmlsdGVyLmlkICYmICQuaXNBcnJheShmaWx0ZXIuaWQpICYmIGZpbHRlci5pZC5sZW5ndGggPj0gdGhyZXNob2xkKSB7XG4gICAgICAgICAgICAgICAgZ2V0T3B0aW9ucy51cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpICsgJz9fbWV0aG9kPUdFVCc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGlkOiBmaWx0ZXIuaWQgfSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRGaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGEgc2luZ2xlIGVuZCB1c2VyIGluIHlvdXIgdGVhbSwgYmFzZWQgb24gdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRCeUlkOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcHVibGljQVBJLmdldCh7IGlkOiB1c2VySWQgfSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG5cblxuXG5cbiIsIi8qKlxuICpcbiAqICMjVmFyaWFibGVzIEFQSSBTZXJ2aWNlXG4gKlxuICogVXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSB0byByZWFkLCB3cml0ZSwgYW5kIHNlYXJjaCBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLlxuICpcbiAqICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJ1xuICogICAgICAgICAgIH1cbiAqICAgICAgfSk7XG4gKiAgICAgcm0uZ2V0UnVuKClcbiAqICAgICAgIC50aGVuKGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgdmFyIHZzID0gcm0ucnVuLnZhcmlhYmxlcygpO1xuICogICAgICAgICAgdnMuc2F2ZSh7c2FtcGxlX2ludDogNH0pO1xuICogICAgICAgIH0pO1xuICpcbiAqL1xuXG5cbiAndXNlIHN0cmljdCc7XG5cbiB2YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG4gdmFyIHJ1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9ydW4tdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcnVucyBvYmplY3QgdG8gd2hpY2ggdGhlIHZhcmlhYmxlIGZpbHRlcnMgYXBwbHkuIERlZmF1bHRzIHRvIG51bGwuXG4gICAgICAgICAqIEB0eXBlIHtydW5TZXJ2aWNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcnVuU2VydmljZTogbnVsbFxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ3ZhcmlhYmxlcy8nO1xuICAgIH07XG5cbiAgICB2YXIgYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9IHtcbiAgICAgICAgdXJsOiBnZXRVUkxcbiAgICB9O1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICBodHRwLnNwbGl0R2V0ID0gcnV0aWwuc3BsaXRHZXRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB2YWx1ZXMgZm9yIGEgdmFyaWFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMubG9hZCgnc2FtcGxlX2ludCcpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCl7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgY29udGFpbnMgdGhlIHZhbHVlIG9mIHNhbXBsZV9pbnRcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgdmFyaWFibGVgIE5hbWUgb2YgdmFyaWFibGUgdG8gbG9hZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHZhcmlhYmxlLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG91dHB1dE1vZGlmaWVyLCAkLmV4dGVuZCh7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IGdldFVSTCgpICsgdmFyaWFibGUgKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHZhcmlhYmxlcywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxdWVyeWAgb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KFsncHJpY2UnLCAnc2FsZXMnXSlcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgaXMgYW4gb2JqZWN0IHdpdGggdGhlIHZhbHVlcyBvZiB0aGUgcmVxdWVzdGVkIHZhcmlhYmxlczogdmFsLnByaWNlLCB2YWwuc2FsZXNcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoeyBpbmNsdWRlOlsncHJpY2UnLCAnc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IGBxdWVyeWAgVGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgcmVxdWVzdGVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9RdWVyeSBhbmQgb3V0cHV0TW9kaWZpZXIgYXJlIGJvdGggcXVlcnlzdHJpbmdzIGluIHRoZSB1cmw7IG9ubHkgY2FsbGluZyB0aGVtIG91dCBzZXBhcmF0ZWx5IGhlcmUgdG8gYmUgY29uc2lzdGVudCB3aXRoIHRoZSBvdGhlciBjYWxsc1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KHF1ZXJ5KSkge1xuICAgICAgICAgICAgICAgIHF1ZXJ5ID0geyBpbmNsdWRlOiBxdWVyeSB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJC5leHRlbmQocXVlcnksIG91dHB1dE1vZGlmaWVyKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KHF1ZXJ5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgdmFsdWVzIHRvIG1vZGVsIHZhcmlhYmxlcy4gT3ZlcndyaXRlcyBleGlzdGluZyB2YWx1ZXMuIE5vdGUgdGhhdCB5b3UgY2FuIG9ubHkgdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoQW4gYWx0ZXJuYXRlIHdheSB0byB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlzIHRvIGNhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwgYW5kIG1ha2Ugc3VyZSB0aGF0IHRoZSBtZXRob2QgcGVyc2lzdHMgdGhlIHZhcmlhYmxlcy4gU2VlIGBkb2AsIGBzZXJpYWxgLCBhbmQgYHBhcmFsbGVsYCBpbiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgZm9yIGNhbGxpbmcgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMuc2F2ZSgncHJpY2UnLCA0KTtcbiAgICAgICAgICogICAgICB2cy5zYXZlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgdmFyaWFibGVgIEFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgbW9kZWwgdmFyaWFibGVzIGFuZCB0aGUgdmFsdWVzIHRvIHNhdmUuIEFsdGVybmF0aXZlbHksIGEgc3RyaW5nIHdpdGggdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbGAgKE9wdGlvbmFsKSBJZiBwYXNzaW5nIGEgc3RyaW5nIGZvciBgdmFyaWFibGVgLCB1c2UgdGhpcyBhcmd1bWVudCBmb3IgdGhlIHZhbHVlIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uICh2YXJpYWJsZSwgdmFsLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW3ZhcmlhYmxlXSA9IHZhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoLmNhbGwodGhpcywgYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdCBBdmFpbGFibGUgdW50aWwgdW5kZXJseWluZyBBUEkgc3VwcG9ydHMgUFVULiBPdGhlcndpc2Ugc2F2ZSB3b3VsZCBiZSBQVVQgYW5kIG1lcmdlIHdvdWxkIGJlIFBBVENIXG4gICAgICAgIC8vICpcbiAgICAgICAgLy8gICogU2F2ZSB2YWx1ZXMgdG8gdGhlIGFwaS4gTWVyZ2VzIGFycmF5cywgYnV0IG90aGVyd2lzZSBzYW1lIGFzIHNhdmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSB2YXJpYWJsZSBPYmplY3Qgd2l0aCBhdHRyaWJ1dGVzLCBvciBzdHJpbmcga2V5XG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSB2YWwgT3B0aW9uYWwgaWYgcHJldiBwYXJhbWV0ZXIgd2FzIGEgc3RyaW5nLCBzZXQgdmFsdWUgaGVyZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAZXhhbXBsZVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSgncHJpY2UnLCA0KTtcblxuICAgICAgICAvLyBtZXJnZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgLy8gICAgIHZhciBhdHRycztcbiAgICAgICAgLy8gICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIC8vICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgIC8vICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAvLyAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAvLyAgICAgfVxuICAgICAgICAvLyAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAvLyAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICAvLyB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNXb3JsZCBBUEkgQWRhcHRlclxuICpcbiAqIEEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsIC0tIGluY2x1ZGluZyBzZXR0aW5nIHZhcmlhYmxlcywgbWFraW5nIGRlY2lzaW9ucywgYW5kIGNhbGxpbmcgb3BlcmF0aW9ucy4gRm9yIGJ1aWxkaW5nIG11bHRpcGxheWVyIHNpbXVsYXRpb25zIHlvdSB0eXBpY2FsbHkgd2FudCBtdWx0aXBsZSBlbmQgdXNlcnMgdG8gc2hhcmUgdGhlIHNhbWUgc2V0IG9mIGludGVyYWN0aW9ucywgYW5kIHdvcmsgd2l0aGluIGEgY29tbW9uIHN0YXRlLiBFcGljZW50ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUgXCJ3b3JsZHNcIiB0byBoYW5kbGUgc3VjaCBjYXNlcy4gT25seSBbdGVhbSBwcm9qZWN0c10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIGNhbiBiZSBtdWx0aXBsYXllci5cbiAqXG4gKiBUaGUgV29ybGQgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUsIGFjY2VzcywgYW5kIG1hbmlwdWxhdGUgbXVsdGlwbGF5ZXIgd29ybGRzIHdpdGhpbiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBZb3UgY2FuIHVzZSB0aGlzIHRvIGFkZCBhbmQgcmVtb3ZlIGVuZCB1c2VycyBmcm9tIHRoZSB3b3JsZCwgYW5kIHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgcmVtb3ZlIHRoZWlyIHJ1bnMuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4gKFRoZSByZWxhdGVkIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyLykgcHJvdmlkZXMgYW4gZWFzeSB3YXkgdG8gYWNjZXNzIHJ1bnMgYW5kIHdvcmxkcyBmb3IgcGFydGljdWxhciBlbmQgdXNlcnMsIHNvIGlzIHR5cGljYWxseSB1c2VkIGluIHBhZ2VzIHRoYXQgZW5kIHVzZXJzIHdpbGwgaW50ZXJhY3Qgd2l0aC4pXG4gKlxuICogQXMgd2l0aCBhbGwgdGhlIG90aGVyIFtBUEkgQWRhcHRlcnNdKC4uLy4uLyksIGFsbCBtZXRob2RzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBXb3JsZCBBUEkgU2VydmljZSBkZWZhdWx0cy5cbiAqXG4gKiBUbyB1c2UgdGhlIFdvcmxkIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSksIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKSwgYW5kIGdyb3VwICgqKkdyb3VwIE5hbWUqKikuXG4gKlxuICogICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gKiAgICAgICB3YS5jcmVhdGUoKVxuICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAqICAgICAgICAgICAgICAvLyBjYWxsIG1ldGhvZHMsIGUuZy4gd2EuYWRkVXNlcnMoKVxuICogICAgICAgICAgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG4vLyB2YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGFwaUJhc2UgPSAnbXVsdGlwbGF5ZXIvJztcbnZhciBhc3NpZ25tZW50RW5kcG9pbnQgPSBhcGlCYXNlICsgJ2Fzc2lnbic7XG52YXIgYXBpRW5kcG9pbnQgPSBhcGlCYXNlICsgJ3dvcmxkJztcbnZhciBwcm9qZWN0RW5kcG9pbnQgPSBhcGlCYXNlICsgJ3Byb2plY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkoeyBzeW5jaHJvbm91czogdHJ1ZSB9KTtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgZ3JvdXA6IHVuZGVmaW5lZCxcblxuICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIHJ1bnMgaW4gdGhpcyB3b3JsZC4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbW9kZWw6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JpdGVyaWEgYnkgd2hpY2ggdG8gZmlsdGVyIHdvcmxkLiBDdXJyZW50bHkgb25seSBzdXBwb3J0cyB3b3JsZC1pZHMgYXMgZmlsdGVycy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlbmllbmNlIGFsaWFzIGZvciBmaWx0ZXJcbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3BcbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMucHJvamVjdCA9IHVybENvbmZpZy5wcm9qZWN0UGF0aDtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBzZXRJZEZpbHRlck9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmlkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gd29ybGQgaWQgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdC4gVGhpcyBjb3VsZCBoYXBwZW4gaWYgdGhlIHVzZXIgaXMgbm90IGFzc2lnbmVkIHRvIGEgd29ybGQgYW5kIGlzIHRyeWluZyB0byB3b3JrIHdpdGggcnVucyBmcm9tIHRoYXQgd29ybGQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAoIW9wdGlvbnMubW9kZWwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gbW9kZWwgc3BlY2lmaWVkIHRvIGdldCB0aGUgY3VycmVudCBydW4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENyZWF0ZXMgYSBuZXcgV29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBVc2luZyB0aGlzIG1ldGhvZCBpcyByYXJlLiBJdCBpcyBtb3JlIGNvbW1vbiB0byBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkgd2hpbGUgeW91IGBhdXRvQXNzaWduKClgIGVuZCB1c2VycyB0byB3b3JsZHMuIChJbiB0aGlzIGNhc2UsIGNvbmZpZ3VyYXRpb24gZGF0YSBmb3IgdGhlIHdvcmxkLCBzdWNoIGFzIHRoZSByb2xlcywgYXJlIHJlYWQgZnJvbSB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9uLCBmb3IgZXhhbXBsZSBieSBgZ2V0UHJvamVjdFNldHRpbmdzKClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSh7XG4gICAgICAgICogICAgICAgICAgIHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddXG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBjcmVhdGUgdGhlIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwYCAoT3B0aW9uYWwpIFRoZSAqKkdyb3VwIE5hbWUqKiB0byBjcmVhdGUgdGhpcyB3b3JsZCB1bmRlci4gT25seSBlbmQgdXNlcnMgaW4gdGhpcyBncm91cCBhcmUgZWxpZ2libGUgdG8gam9pbiB0aGUgd29ybGQuIE9wdGlvbmFsIGhlcmU7IHJlcXVpcmVkIHdoZW4gaW5zdGFudGlhdGluZyB0aGUgc2VydmljZSAoYG5ldyBGLnNlcnZpY2UuV29ybGQoKWApLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfSk7XG4gICAgICAgICAgICB2YXIgd29ybGRBcGlQYXJhbXMgPSBbJ3Njb3BlJywgJ2ZpbGVzJywgJ3JvbGVzJywgJ29wdGlvbmFsUm9sZXMnLCAnbWluVXNlcnMnLCAnZ3JvdXAnLCAnbmFtZSddO1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHdvcmxkQXBpUGFyYW1zKTtcblxuICAgICAgICAgICAgLy8gYWNjb3VudCBhbmQgcHJvamVjdCBnbyBpbiB0aGUgYm9keSwgbm90IGluIHRoZSB1cmxcbiAgICAgICAgICAgICQuZXh0ZW5kKHBhcmFtcywgX3BpY2soc2VydmljZU9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pKTtcblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBVcGRhdGVzIGEgV29ybGQsIGZvciBleGFtcGxlIHRvIHJlcGxhY2UgdGhlIHJvbGVzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgeW91IGNvbXBsZXRlIHdvcmxkIGNvbmZpZ3VyYXRpb24gYXQgdGhlIHByb2plY3QgbGV2ZWwsIHJhdGhlciB0aGFuIGF0IHRoZSB3b3JsZCBsZXZlbC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguIEhvd2V2ZXIsIHRoaXMgbWV0aG9kIGlzIGF2YWlsYWJsZSBpZiB5b3UgbmVlZCB0byB1cGRhdGUgdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBwYXJ0aWN1bGFyIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnVwZGF0ZSh7IHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHVwZGF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMubmFtZWAgQSBzdHJpbmcgaWRlbnRpZmllciBmb3IgdGhlIGxpbmtlZCBlbmQgdXNlcnMsIGZvciBleGFtcGxlLCBcIm5hbWVcIjogXCJPdXIgVGVhbVwiLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHdoaXRlbGlzdCA9IFsncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycyddO1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHVwZGF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zIHx8IHt9LCB3aGl0ZWxpc3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChwYXJhbXMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYW4gZXhpc3Rpbmcgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBUaGlzIGZ1bmN0aW9uIG9wdGlvbmFsbHkgdGFrZXMgb25lIGFyZ3VtZW50LiBJZiB0aGUgYXJndW1lbnQgaXMgYSBzdHJpbmcsIGl0IGlzIHRoZSBpZCBvZiB0aGUgd29ybGQgdG8gZGVsZXRlLiBJZiB0aGUgYXJndW1lbnQgaXMgYW4gb2JqZWN0LCBpdCBpcyB0aGUgb3ZlcnJpZGUgZm9yIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmRlbGV0ZSgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUsIG9yIG9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAob3B0aW9ucyAmJiAodHlwZW9mIG9wdGlvbnMgPT09ICdzdHJpbmcnKSkgPyB7IGZpbHRlcjogb3B0aW9ucyB9IDoge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRlbGV0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGRlbGV0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBjdXJyZW50IGluc3RhbmNlIG9mIHRoZSBXb3JsZCBBUEkgQWRhcHRlciAoaW5jbHVkaW5nIGFsbCBzdWJzZXF1ZW50IGZ1bmN0aW9uIGNhbGxzLCB1bnRpbCB0aGUgY29uZmlndXJhdGlvbiBpcyB1cGRhdGVkIGFnYWluKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoey4uLn0pLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogJzEyMycgfSkuYWRkVXNlcih7IHVzZXJJZDogJzEyMycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgY29uZmlnYCBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gdXNlIGluIHVwZGF0aW5nIGV4aXN0aW5nIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZUNvbmZpZzogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMsIGNvbmZpZyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIExpc3RzIGFsbCB3b3JsZHMgZm9yIGEgZ2l2ZW4gYWNjb3VudCwgcHJvamVjdCwgYW5kIGdyb3VwLiBBbGwgdGhyZWUgYXJlIHJlcXVpcmVkLCBhbmQgaWYgbm90IHNwZWNpZmllZCBhcyBwYXJhbWV0ZXJzLCBhcmUgcmVhZCBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJ0ZWFtMVwiXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5saXN0KCk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJvdGhlci1ncm91cC1uYW1lXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoeyBncm91cDogJ290aGVyLWdyb3VwLW5hbWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBsaXN0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGFsbCB3b3JsZHMgdGhhdCBhbiBlbmQgdXNlciBiZWxvbmdzIHRvIGZvciBhIGdpdmVuIGFjY291bnQgKHRlYW0pLCBwcm9qZWN0LCBhbmQgZ3JvdXAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZ2V0V29ybGRzRm9yVXNlcignYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJylcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZHMgYXJlIGJlaW5nIHJldHJpZXZlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldFdvcmxkc0ZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YXIgZmlsdGVycyA9ICQuZXh0ZW5kKFxuICAgICAgICAgICAgICAgIF9waWNrKGdldE9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pLFxuICAgICAgICAgICAgICAgIHsgdXNlcklkOiB1c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGluZm9ybWF0aW9uIGZvciBhIHNwZWNpZmljIHdvcmxkLiBBbGwgZnVydGhlciBjYWxscyB0byB0aGUgd29ybGQgc2VydmljZSB3aWxsIHVzZSB0aGUgaWQgcHJvdmlkZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgd29ybGRJZGAgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBsb2FkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgd29ybGRpZCB0byBsb2FkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy8nIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQWRkcyBhbiBlbmQgdXNlciBvciBsaXN0IG9mIGVuZCB1c2VycyB0byBhIGdpdmVuIHdvcmxkLiBUaGUgZW5kIHVzZXIgbXVzdCBiZSBhIG1lbWJlciBvZiB0aGUgYGdyb3VwYCB0aGF0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlclxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoWydiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2Vycyh7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdWUCBTYWxlcycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBzZXZlcmFsIHVzZXJzXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgeyB1c2VySWQ6ICdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ1ZQIE1hcmtldGluZycgfSxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgRW5naW5lZXJpbmcnIH1cbiAgICAgICAgKiAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgICAgICAvLyBhZGQgb25lIHVzZXIgdG8gYSBzcGVjaWZpYyB3b3JsZFxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB7IGZpbHRlcjogd29ybGQuaWQgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdHxhcnJheX0gYHVzZXJzYCBVc2VyIGlkLCBhcnJheSBvZiB1c2VyIGlkcywgb2JqZWN0LCBvciBhcnJheSBvZiBvYmplY3RzIG9mIHRoZSB1c2VycyB0byBhZGQgdG8gdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJzLnJvbGVgIFRoZSBgcm9sZWAgdGhlIHVzZXIgc2hvdWxkIGhhdmUgaW4gdGhlIHdvcmxkLiBJdCBpcyB1cCB0byB0aGUgY2FsbGVyIHRvIGVuc3VyZSwgaWYgbmVlZGVkLCB0aGF0IHRoZSBgcm9sZWAgcGFzc2VkIGluIGlzIG9uZSBvZiB0aGUgYHJvbGVzYCBvciBgb3B0aW9uYWxSb2xlc2Agb2YgdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSB3b3JsZCB0byB3aGljaCB0aGUgdXNlcnMgc2hvdWxkIGJlIGFkZGVkLiBJZiBub3Qgc3BlY2lmaWVkLCB0aGUgZmlsdGVyIHBhcmFtZXRlciBvZiB0aGUgYG9wdGlvbnNgIG9iamVjdCBpcyB1c2VkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgYWRkVXNlcnM6IGZ1bmN0aW9uICh1c2Vycywgd29ybGRJZCwgb3B0aW9ucykge1xuXG4gICAgICAgICAgICBpZiAoIXVzZXJzKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhIGxpc3Qgb2YgdXNlcnMgdG8gYWRkIHRvIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBub3JtYWxpemUgdGhlIGxpc3Qgb2YgdXNlcnMgdG8gYW4gYXJyYXkgb2YgdXNlciBvYmplY3RzXG4gICAgICAgICAgICB1c2VycyA9ICQubWFwKFtdLmNvbmNhdCh1c2VycyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KHUpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1ICE9PSAnc3RyaW5nJyAmJiAhaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTb21lIG9mIHRoZSB1c2VycyBpbiB0aGUgbGlzdCBhcmUgbm90IGluIHRoZSB2YWxpZCBmb3JtYXQ6ICcgKyB1KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gaXNPYmplY3QgPyB1IDogeyB1c2VySWQ6IHUgfTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBjaGVjayBpZiBvcHRpb25zIHdlcmUgcGFzc2VkIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHdvcmxkSWQpICYmICFvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHdvcmxkSWQ7XG4gICAgICAgICAgICAgICAgd29ybGRJZCA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICAvLyB3ZSBtdXN0IGhhdmUgb3B0aW9ucyBieSBub3dcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygd29ybGRJZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvdXNlcnMnIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QodXNlcnMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIHJvbGUgb2YgYW4gZW5kIHVzZXIgaW4gYSBnaXZlbiB3b3JsZC4gKFlvdSBjYW4gb25seSB1cGRhdGUgb25lIGVuZCB1c2VyIGF0IGEgdGltZS4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuY3JlYXRlKCkudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgIHdhLnVwZGF0ZVVzZXIoeyB1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCByb2xlOiAnbGVhZGVyJyB9KTtcbiAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHVzZXJgIFVzZXIgb2JqZWN0IHdpdGggYHVzZXJJZGAgYW5kIHRoZSBuZXcgYHJvbGVgLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICghdXNlciB8fCAhdXNlci51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHBhc3MgYSB1c2VySWQgdG8gdXBkYXRlIGZyb20gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcGF0Y2hPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goX3BpY2sodXNlciwgJ3JvbGUnKSwgcGF0Y2hPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZW1vdmVzIGFuIGVuZCB1c2VyIGZyb20gYSBnaXZlbiB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5yZW1vdmVVc2VyKCdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoeyB1c2VySWQ6ICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdHxzdHJpbmd9IGB1c2VyYCBUaGUgYHVzZXJJZGAgb2YgdGhlIHVzZXIgdG8gcmVtb3ZlIGZyb20gdGhlIHdvcmxkLCBvciBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgYHVzZXJJZGAgZmllbGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdXNlciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICB1c2VyID0geyB1c2VySWQ6IHVzZXIgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHJ1biBpZCBvZiBjdXJyZW50IHJ1biBmb3IgdGhlIGdpdmVuIHdvcmxkLiBJZiB0aGUgd29ybGQgZG9lcyBub3QgaGF2ZSBhIHJ1biwgY3JlYXRlcyBhIG5ldyBvbmUgYW5kIHJldHVybnMgdGhlIHJ1biBpZC5cbiAgICAgICAgKlxuICAgICAgICAqIFJlbWVtYmVyIHRoYXQgYSBbcnVuXSguLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwuIEluIHRoZSBjYXNlIG9mIG11bHRpcGxheWVyIHByb2plY3RzLCB0aGUgcnVuIGlzIHNoYXJlZCBieSBhbGwgZW5kIHVzZXJzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRDdXJyZW50UnVuSWQoeyBtb2RlbDogJ21vZGVsLnB5JyB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRSdW5JZDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3J1bicgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoX3BpY2soZ2V0T3B0aW9ucywgJ21vZGVsJyksIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBmb3IgdGhlIGdpdmVuIGVuZCB1c2VyIGluIHRoZSBnaXZlbiBncm91cC4gQnJpbmdzIHRoaXMgbW9zdCByZWNlbnQgd29ybGQgaW50byBtZW1vcnkgaWYgbmVlZGVkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIHVzZSBkYXRhIGZyb20gd29ybGRcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSBjdXJyZW50IChtb3N0IHJlY2VudCkgd29ybGQgaXMgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cC4gSWYgbm90IHByb3ZpZGVkLCBkZWZhdWx0cyB0byB0aGUgZ3JvdXAgdXNlZCB0byBjcmVhdGUgdGhlIHNlcnZpY2UuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRXb3JsZEZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkc0ZvclVzZXIodXNlcklkLCB7IGdyb3VwOiBncm91cE5hbWUgfSlcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGFzc3VtZSB0aGUgbW9zdCByZWNlbnQgd29ybGQgYXMgdGhlICdhY3RpdmUnIHdvcmxkXG4gICAgICAgICAgICAgICAgICAgIHdvcmxkcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7IHJldHVybiBuZXcgRGF0ZShiLmxhc3RNb2RpZmllZCkgLSBuZXcgRGF0ZShhLmxhc3RNb2RpZmllZCk7IH0pO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VycmVudFdvcmxkID0gd29ybGRzWzBdO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50V29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9ICBjdXJyZW50V29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShjdXJyZW50V29ybGQsIG1lKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIHRoZSBjdXJyZW50IHJ1biBmcm9tIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIChOb3RlIHRoYXQgdGhlIHdvcmxkIGlkIHJlbWFpbnMgcGFydCBvZiB0aGUgcnVuIHJlY29yZCwgaW5kaWNhdGluZyB0aGF0IHRoZSBydW4gd2FzIGZvcm1lcmx5IGFuIGFjdGl2ZSBydW4gZm9yIHRoZSB3b3JsZC4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmRlbGV0ZVJ1bignc2FtcGxlLXdvcmxkLWlkJyk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSBgd29ybGRJZGAgb2YgdGhlIHdvcmxkIGZyb20gd2hpY2ggdGhlIGN1cnJlbnQgcnVuIGlzIGJlaW5nIGRlbGV0ZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGVSdW46IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBydW4gZm9yIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgd2EubmV3UnVuRm9yV29ybGQod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgd29ybGRJZCBpbiB3aGljaCB3ZSBjcmVhdGUgdGhlIG5ldyBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIG5ld1J1bkZvcldvcmxkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGN1cnJlbnRSdW5PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IGZpbHRlcjogd29ybGRJZCB8fCBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IoY3VycmVudFJ1bk9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kZWxldGVSdW4od29ybGRJZCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5nZXRDdXJyZW50UnVuSWQoY3VycmVudFJ1bk9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEFzc2lnbnMgZW5kIHVzZXJzIHRvIHdvcmxkcywgY3JlYXRpbmcgbmV3IHdvcmxkcyBhcyBhcHByb3ByaWF0ZSwgYXV0b21hdGljYWxseS4gQXNzaWducyBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cCwgYW5kIGNyZWF0ZXMgbmV3IHdvcmxkcyBhcyBuZWVkZWQgYmFzZWQgb24gdGhlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbiAocm9sZXMsIG9wdGlvbmFsIHJvbGVzLCBhbmQgbWluaW11bSBlbmQgdXNlcnMgcGVyIHdvcmxkKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5hdXRvQXNzaWduKCk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBhdXRvQXNzaWduOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhc3NpZ25tZW50RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBwYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3B0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgcHJvamVjdDogb3B0LnByb2plY3QsXG4gICAgICAgICAgICAgICAgZ3JvdXA6IG9wdC5ncm91cFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKG9wdC5tYXhVc2Vycykge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5tYXhVc2VycyA9IG9wdC5tYXhVc2VycztcbiAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgb3B0KTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBwcm9qZWN0J3Mgd29ybGQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgZXZlcnkgaW50ZXJhY3Rpb24gd2l0aCB5b3VyIHByb2plY3QgdXNlcyB0aGUgc2FtZSBjb25maWd1cmF0aW9uIG9mIGVhY2ggd29ybGQuIEZvciBleGFtcGxlLCBlYWNoIHdvcmxkIGluIHlvdXIgcHJvamVjdCBwcm9iYWJseSBoYXMgdGhlIHNhbWUgcm9sZXMgZm9yIGVuZCB1c2Vycy4gQW5kIHlvdXIgcHJvamVjdCBpcyBwcm9iYWJseSBlaXRoZXIgY29uZmlndXJlZCBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgc2hhcmUgdGhlIHNhbWUgd29ybGQgKGFuZCBydW4pLCBvciBzbWFsbGVyIHNldHMgb2YgZW5kIHVzZXJzIHNoYXJlIHdvcmxkcyDigJQgYnV0IG5vdCBib3RoLlxuICAgICAgICAqXG4gICAgICAgICogKFRoZSBbTXVsdGlwbGF5ZXIgUHJvamVjdCBSRVNUIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL211bHRpcGxheWVyX3Byb2plY3QvKSBhbGxvd3MgeW91IHRvIHNldCB0aGVzZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb25zLiBUaGUgV29ybGQgQWRhcHRlciBzaW1wbHkgcmV0cmlldmVzIHRoZW0sIGZvciBleGFtcGxlIHNvIHRoZXkgY2FuIGJlIHVzZWQgaW4gYXV0by1hc3NpZ25tZW50IG9mIGVuZCB1c2VycyB0byB3b3JsZHMuKVxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmdldFByb2plY3RTZXR0aW5ncygpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHNldHRpbmdzKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5yb2xlcyk7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5vcHRpb25hbFJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0UHJvamVjdFNldHRpbmdzOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChwcm9qZWN0RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIG9wdC51cmwgKz0gW29wdC5hY2NvdW50LCBvcHQucHJvamVjdF0uam9pbignLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQobnVsbCwgb3B0KTtcbiAgICAgICAgfVxuXG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29va2llIFN0b3JhZ2UgU2VydmljZVxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgIHZhciBwZW9wbGUgPSByZXF1aXJlKCdjb29raWUtc3RvcmUnKSh7IHJvb3Q6ICdwZW9wbGUnIH0pO1xuICAgICAgICBwZW9wbGVcbiAgICAgICAgICAgIC5zYXZlKHtsYXN0TmFtZTogJ3NtaXRoJyB9KVxuXG4gKi9cblxuXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5hbWUgb2YgY29sbGVjdGlvblxuICAgICAgICAgKiBAdHlwZSB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHJvb3Q6ICcvJyxcblxuICAgICAgICBkb21haW46ICcuZm9yaW8uY29tJ1xuICAgIH07XG4gICAgdGhpcy5zZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIC8vICogVEJEXG4gICAgICAgIC8vICAqIFF1ZXJ5IGNvbGxlY3Rpb247IHVzZXMgTW9uZ29EQiBzeW50YXhcbiAgICAgICAgLy8gICogQHNlZSAgPFRCRDogRGF0YSBBUEkgVVJMPlxuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IHFzIFF1ZXJ5IEZpbHRlclxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IGxpbWl0ZXJzIEBzZWUgPFRCRDogdXJsIGZvciBsaW1pdHMsIHBhZ2luZyBldGM+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBleGFtcGxlXG4gICAgICAgIC8vICAqICAgICBjcy5xdWVyeShcbiAgICAgICAgLy8gICogICAgICB7IG5hbWU6ICdKb2huJywgY2xhc3NOYW1lOiAnQ1NDMTAxJyB9LFxuICAgICAgICAvLyAgKiAgICAgIHtsaW1pdDogMTB9XG4gICAgICAgIC8vICAqICAgICApXG5cbiAgICAgICAgLy8gcXVlcnk6IGZ1bmN0aW9uIChxcywgbGltaXRlcnMpIHtcblxuICAgICAgICAvLyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGNvb2tpZSB2YWx1ZVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5ICAgSWYgZ2l2ZW4gYSBrZXkgc2F2ZSB2YWx1ZXMgdW5kZXIgaXQsIGlmIGdpdmVuIGFuIG9iamVjdCBkaXJlY3RseSwgc2F2ZSB0byB0b3AtbGV2ZWwgYXBpXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gdmFsdWUgKE9wdGlvbmFsKVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIHNlcnZpY2Ugb3B0aW9uc1xuICAgICAgICAgKlxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgc2F2ZWQgdmFsdWVcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnNldCgncGVyc29uJywgeyBmaXJzdE5hbWU6ICdqb2huJywgbGFzdE5hbWU6ICdzbWl0aCcgfSk7XG4gICAgICAgICAqICAgICBjcy5zZXQoeyBuYW1lOidzbWl0aCcsIGFnZTonMzInIH0pO1xuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHNldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5zZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSBzZXRPcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2V0T3B0aW9ucy5yb290O1xuXG4gICAgICAgICAgICBkb2N1bWVudC5jb29raWUgPSBlbmNvZGVVUklDb21wb25lbnQoa2V5KSArICc9JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuY29kZVVSSUNvbXBvbmVudCh2YWx1ZSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG5cbiAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9hZCBjb29raWUgdmFsdWVcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSAgIElmIGdpdmVuIGEga2V5IHNhdmUgdmFsdWVzIHVuZGVyIGl0LCBpZiBnaXZlbiBhbiBvYmplY3QgZGlyZWN0bHksIHNhdmUgdG8gdG9wLWxldmVsIGFwaVxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgdmFsdWUgc3RvcmVkXG4gICAgICAgICAqXG4gICAgICAgICAqIEBleGFtcGxlXG4gICAgICAgICAqICAgICBjcy5nZXQoJ3BlcnNvbicpO1xuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgY29va2llUmVnID0gbmV3IFJlZ0V4cCgnKD86KD86XnwuKjspXFxcXHMqJyArIGVuY29kZVVSSUNvbXBvbmVudChrZXkpLnJlcGxhY2UoL1tcXC1cXC5cXCtcXCpdL2csICdcXFxcJCYnKSArICdcXFxccypcXFxcPVxcXFxzKihbXjtdKikuKiQpfF4uKiQnKTtcbiAgICAgICAgICAgIHZhciB2YWwgPSBkb2N1bWVudC5jb29raWUucmVwbGFjZShjb29raWVSZWcsICckMScpO1xuICAgICAgICAgICAgdmFsID0gZGVjb2RlVVJJQ29tcG9uZW50KHZhbCkgfHwgbnVsbDtcbiAgICAgICAgICAgIHJldHVybiB2YWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMga2V5IGZyb20gY29sbGVjdGlvblxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGtleSBrZXkgdG8gcmVtb3ZlXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9IGtleSBUaGUga2V5IHJlbW92ZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnJlbW92ZSgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciByZW1PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMuc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9tYWluID0gcmVtT3B0aW9ucy5kb21haW47XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHJlbU9wdGlvbnMucm9vdDtcblxuICAgICAgICAgICAgZG9jdW1lbnQuY29va2llID0gZW5jb2RlVVJJQ29tcG9uZW50KGtleSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICc9OyBleHBpcmVzPVRodSwgMDEgSmFuIDE5NzAgMDA6MDA6MDAgR01UJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGRvbWFpbiA/ICc7IGRvbWFpbj0nICsgZG9tYWluIDogJycpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG4gICAgICAgICAgICByZXR1cm4ga2V5O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIGNvbGxlY3Rpb24gYmVpbmcgcmVmZXJlbmNlZFxuICAgICAgICAgKiBAcmV0dXJuIHsgYXJyYXl9IGtleXMgQWxsIHRoZSBrZXlzIHJlbW92ZWRcbiAgICAgICAgICovXG4gICAgICAgIGRlc3Ryb3k6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhS2V5cyA9IGRvY3VtZW50LmNvb2tpZS5yZXBsYWNlKC8oKD86XnxcXHMqOylbXlxcPV0rKSg/PTt8JCl8Xlxccyp8XFxzKig/OlxcPVteO10qKT8oPzpcXDF8JCkvZywgJycpLnNwbGl0KC9cXHMqKD86XFw9W147XSopPztcXHMqLyk7XG4gICAgICAgICAgICBmb3IgKHZhciBuSWR4ID0gMDsgbklkeCA8IGFLZXlzLmxlbmd0aDsgbklkeCsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvb2tpZUtleSA9IGRlY29kZVVSSUNvbXBvbmVudChhS2V5c1tuSWR4XSk7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmUoY29va2llS2V5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhS2V5cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICAgIERlY2lkZXMgdHlwZSBvZiBzdG9yZSB0byBwcm92aWRlXG4qL1xuXG4ndXNlIHN0cmljdCc7XG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHN0b3JlID0gKGlzTm9kZSkgPyByZXF1aXJlKCcuL3Nlc3Npb24tc3RvcmUnKSA6IHJlcXVpcmUoJy4vY29va2llLXN0b3JlJyk7XG52YXIgc3RvcmUgPSByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHN0b3JlO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgcXV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgIGhlYWRlcnM6IHt9LFxuICAgICAgICBzdGF0dXNDb2RlOiB7XG4gICAgICAgICAgICA0MDQ6ICQubm9vcFxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPTkxZIGZvciBzdHJpbmdzIGluIHRoZSB1cmwuIEFsbCBHRVQgJiBERUxFVEUgcGFyYW1zIGFyZSBydW4gdGhyb3VnaCB0aGlzXG4gICAgICAgICAqIEB0eXBlIHtbdHlwZV0gfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFyYW1ldGVyUGFyc2VyOiBxdXRpbHMudG9RdWVyeUZvcm1hdCxcblxuICAgICAgICAvLyBUbyBhbGxvdyBlcGljZW50ZXIudG9rZW4gYW5kIG90aGVyIHNlc3Npb24gY29va2llcyB0byBiZSBwYXNzZWRcbiAgICAgICAgLy8gd2l0aCB0aGUgcmVxdWVzdHNcbiAgICAgICAgeGhyRmllbGRzOiB7XG4gICAgICAgICAgICB3aXRoQ3JlZGVudGlhbHM6IHRydWVcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciByZXN1bHQgPSBmdW5jdGlvbiAoZCkge1xuICAgICAgICByZXR1cm4gKCQuaXNGdW5jdGlvbihkKSkgPyBkKCkgOiBkO1xuICAgIH07XG5cbiAgICB2YXIgY29ubmVjdCA9IGZ1bmN0aW9uIChtZXRob2QsIHBhcmFtcywgY29ubmVjdE9wdGlvbnMpIHtcbiAgICAgICAgcGFyYW1zID0gcmVzdWx0KHBhcmFtcyk7XG4gICAgICAgIHBhcmFtcyA9ICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSB8fCAkLmlzQXJyYXkocGFyYW1zKSkgPyBKU09OLnN0cmluZ2lmeShwYXJhbXMpIDogcGFyYW1zO1xuXG4gICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRyYW5zcG9ydE9wdGlvbnMsIGNvbm5lY3RPcHRpb25zLCB7XG4gICAgICAgICAgICB0eXBlOiBtZXRob2QsXG4gICAgICAgICAgICBkYXRhOiBwYXJhbXNcbiAgICAgICAgfSk7XG4gICAgICAgIHZhciBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUyA9IFsnZGF0YScsICd1cmwnXTtcbiAgICAgICAgJC5lYWNoKG9wdGlvbnMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAoJC5pc0Z1bmN0aW9uKHZhbHVlKSAmJiAkLmluQXJyYXkoa2V5LCBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9uc1trZXldID0gdmFsdWUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKG9wdGlvbnMubG9nTGV2ZWwgJiYgb3B0aW9ucy5sb2dMZXZlbCA9PT0gJ0RFQlVHJykge1xuICAgICAgICAgICAgY29uc29sZS5sb2cob3B0aW9ucy51cmwpO1xuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3NGbiA9IG9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UsIGFqYXhTdGF0dXMsIGFqYXhSZXEpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgb2xkU3VjY2Vzc0ZuLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGJlZm9yZVNlbmQgPSBvcHRpb25zLmJlZm9yZVNlbmQ7XG4gICAgICAgIG9wdGlvbnMuYmVmb3JlU2VuZCA9IGZ1bmN0aW9uICh4aHIsIHNldHRpbmdzKSB7XG4gICAgICAgICAgICB4aHIucmVxdWVzdFVybCA9IChjb25uZWN0T3B0aW9ucyB8fCB7fSkudXJsO1xuICAgICAgICAgICAgaWYgKGJlZm9yZVNlbmQpIHtcbiAgICAgICAgICAgICAgICBiZWZvcmVTZW5kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuICQuYWpheChvcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgZ2V0OmZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdHRVQnLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuICAgICAgICBzcGxpdEdldDogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIH0sXG4gICAgICAgIHBvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncG9zdCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgcGF0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncGF0Y2gnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHB1dDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwdXQnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKHBhcmFtcywgYWpheE9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vREVMRVRFIGRvZXNuJ3Qgc3VwcG9ydCBib2R5IHBhcmFtcywgYnV0IGpRdWVyeSB0aGlua3MgaXQgZG9lcy5cbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRyYW5zcG9ydE9wdGlvbnMsIGFqYXhPcHRpb25zKTtcbiAgICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1ldGVyUGFyc2VyKHJlc3VsdChwYXJhbXMpKTtcbiAgICAgICAgICAgIGlmICgkLnRyaW0ocGFyYW1zKSkge1xuICAgICAgICAgICAgICAgIHZhciBkZWxpbWl0ZXIgPSAocmVzdWx0KG9wdGlvbnMudXJsKS5pbmRleE9mKCc/JykgPT09IC0xKSA/ICc/JyA6ICcmJztcbiAgICAgICAgICAgICAgICBvcHRpb25zLnVybCA9IHJlc3VsdChvcHRpb25zLnVybCkgKyBkZWxpbWl0ZXIgKyBwYXJhbXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdERUxFVEUnLCBudWxsLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgaGVhZDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydoZWFkJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBvcHRpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ29wdGlvbnMnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHRyYW5zcG9ydCA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9ub2RlLWh0dHAtdHJhbnNwb3J0JykgOiByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbnZhciB0cmFuc3BvcnQgPSByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbm1vZHVsZS5leHBvcnRzID0gdHJhbnNwb3J0O1xuIiwiLyoqXG4vKiBJbmhlcml0IGZyb20gYSBjbGFzcyAodXNpbmcgcHJvdG90eXBlIGJvcnJvd2luZylcbiovXG4ndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIGluaGVyaXQoQywgUCkge1xuICAgIHZhciBGID0gZnVuY3Rpb24gKCkge307XG4gICAgRi5wcm90b3R5cGUgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZSA9IG5ldyBGKCk7XG4gICAgQy5fX3N1cGVyID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDO1xufVxuXG4vKipcbiogU2hhbGxvdyBjb3B5IG9mIGFuIG9iamVjdFxuKi9cbnZhciBleHRlbmQgPSBmdW5jdGlvbiAoZGVzdCAvKiwgdmFyX2FyZ3MqLykge1xuICAgIHZhciBvYmogPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHZhciBjdXJyZW50O1xuICAgIGZvciAodmFyIGogPSAwOyBqPG9iai5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAoIShjdXJyZW50ID0gb2JqW2pdKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkbyBub3Qgd3JhcCBpbm5lciBpbiBkZXN0Lmhhc093blByb3BlcnR5IG9yIGJhZCB0aGluZ3Mgd2lsbCBoYXBwZW5cbiAgICAgICAgLypqc2hpbnQgLVcwODkgKi9cbiAgICAgICAgZm9yICh2YXIga2V5IGluIGN1cnJlbnQpIHtcbiAgICAgICAgICAgIGRlc3Rba2V5XSA9IGN1cnJlbnRba2V5XTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkZXN0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYmFzZSwgcHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgdmFyIHBhcmVudCA9IGJhc2U7XG4gICAgdmFyIGNoaWxkO1xuXG4gICAgY2hpbGQgPSBwcm9wcyAmJiBwcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSA/IHByb3BzLmNvbnN0cnVjdG9yIDogZnVuY3Rpb24gKCkgeyByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IH07XG5cbiAgICAvLyBhZGQgc3RhdGljIHByb3BlcnRpZXMgdG8gdGhlIGNoaWxkIGNvbnN0cnVjdG9yIGZ1bmN0aW9uXG4gICAgZXh0ZW5kKGNoaWxkLCBwYXJlbnQsIHN0YXRpY1Byb3BzKTtcblxuICAgIC8vIGFzc29jaWF0ZSBwcm90b3R5cGUgY2hhaW5cbiAgICBpbmhlcml0KGNoaWxkLCBwYXJlbnQpO1xuXG4gICAgLy8gYWRkIGluc3RhbmNlIHByb3BlcnRpZXNcbiAgICBpZiAocHJvcHMpIHtcbiAgICAgICAgZXh0ZW5kKGNoaWxkLnByb3RvdHlwZSwgcHJvcHMpO1xuICAgIH1cblxuICAgIC8vIGRvbmVcbiAgICByZXR1cm4gY2hpbGQ7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLypqc2hpbnQgbG9vcGZ1bmM6ZmFsc2UgKi9cblxuZnVuY3Rpb24gX3codmFsKSB7XG4gICAgaWYgKHZhbCAmJiB2YWwudGhlbikge1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgIH1cbiAgICB2YXIgcCA9ICQuRGVmZXJyZWQoKTtcbiAgICBwLnJlc29sdmUodmFsKTtcblxuICAgIHJldHVybiBwLnByb21pc2UoKTtcbn1cblxuZnVuY3Rpb24gc2VxKCkge1xuICAgIHZhciBsaXN0ID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmFwcGx5KGFyZ3VtZW50cyk7XG5cbiAgICBmdW5jdGlvbiBuZXh0KHApIHtcbiAgICAgICAgdmFyIGN1ciA9IGxpc3Quc3BsaWNlKDAsMSlbMF07XG5cbiAgICAgICAgaWYgKCFjdXIpIHtcbiAgICAgICAgICAgIHJldHVybiBwO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF93KGN1cihwKSkudGhlbihuZXh0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gKHNlZWQpIHtcbiAgICAgICAgcmV0dXJuIG5leHQoc2VlZCkuZmFpbChzZXEuZmFpbCk7XG4gICAgfTtcbn1cblxuZnVuY3Rpb24gTWFrZVNlcShvYmopIHtcbiAgICB2YXIgcmVzID0ge1xuICAgICAgICBfX2NhbGxzOiBbXSxcblxuICAgICAgICBvcmlnaW5hbDogb2JqLFxuXG4gICAgICAgIHRoZW46IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goZm4pO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIC8vIGNsZWFuIHVwXG4gICAgICAgICAgICB0aGlzLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIF90aGlzLl9fY2FsbHMubGVuZ3RoID0gMDtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBzZXEuYXBwbHkobnVsbCwgdGhpcy5fX2NhbGxzKSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGZhaWw6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgc2VxLmZhaWwgPSBmbjtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBmdW5jTWFrZXIgPSBmdW5jdGlvbiAocCwgb2JqKSB7XG4gICAgICAgIHZhciBmbiA9IG9ialtwXS5iaW5kKG9iaik7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goRnVuY3Rpb24uYmluZC5hcHBseShmbiwgW251bGxdLmNvbmNhdChhcmdzKSkpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH07XG4gICAgfTtcblxuICAgIGZvciAodmFyIHByb3AgaW4gb2JqKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygb2JqW3Byb3BdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXNbcHJvcF0gPSBmdW5jTWFrZXIocHJvcCwgb2JqKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlc1twcm9wXSA9IG9ialtwcm9wXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gTWFrZVNlcTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgX3BpY2s6IGZ1bmN0aW9uIChvYmosIHByb3BzKSB7XG4gICAgICAgIHZhciByZXMgPSB7fTtcbiAgICAgICAgZm9yICh2YXIgcCBpbiBvYmopIHtcbiAgICAgICAgICAgIGlmIChwcm9wcy5pbmRleE9mKHApICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIHJlc1twXSA9IG9ialtwXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxufTtcbiIsIi8qKlxuICogVXRpbGl0aWVzIGZvciB3b3JraW5nIHdpdGggcXVlcnkgc3RyaW5nc1xuKi9cbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSAoZnVuY3Rpb24gKCkge1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHRvIG1hdHJpeCBmb3JtYXRcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBxcyBPYmplY3QgdG8gY29udmVydCB0byBxdWVyeSBzdHJpbmdcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ30gICAgTWF0cml4LWZvcm1hdCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuICAgICAgICB0b01hdHJpeEZvcm1hdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCB8fCBxcyA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJzsnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgdmFyIE9QRVJBVE9SUyA9IFsnPCcsICc+JywgJyEnXTtcbiAgICAgICAgICAgICQuZWFjaChxcywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnc3RyaW5nJyB8fCAkLmluQXJyYXkoJC50cmltKHZhbHVlKS5jaGFyQXQoMCksIE9QRVJBVE9SUykgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gJz0nICsgdmFsdWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciBtdHJ4ID0gJzsnICsgcmV0dXJuQXJyYXkuam9pbignOycpO1xuICAgICAgICAgICAgcmV0dXJuIG10cng7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHN0cmluZ3MvYXJyYXlzL29iamVjdHMgdG8gdHlwZSAnYT1iJmI9YydcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b1F1ZXJ5Rm9ybWF0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgJC5lYWNoKHFzLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmICgkLmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUuam9pbignLCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICAvL01vc3RseSBmb3IgZGF0YSBhcGlcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBKU09OLnN0cmluZ2lmeSh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgJz0nICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciByZXN1bHQgPSByZXR1cm5BcnJheS5qb2luKCcmJyk7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyBzdHJpbmdzIG9mIHR5cGUgJ2E9YiZiPWMnIHRvIHsgYTpiLCBiOmN9XG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHFzXG4gICAgICAgICAqIEByZXR1cm4ge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHFzVG9PYmplY3Q6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQgfHwgcXMgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcXNBcnJheSA9IHFzLnNwbGl0KCcmJyk7XG4gICAgICAgICAgICB2YXIgcmV0dXJuT2JqID0ge307XG4gICAgICAgICAgICAkLmVhY2gocXNBcnJheSwgZnVuY3Rpb24gKGluZGV4LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBxS2V5ID0gdmFsdWUuc3BsaXQoJz0nKVswXTtcbiAgICAgICAgICAgICAgICB2YXIgcVZhbCA9IHZhbHVlLnNwbGl0KCc9JylbMV07XG5cbiAgICAgICAgICAgICAgICBpZiAocVZhbC5pbmRleE9mKCcsJykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHFWYWwgPSBxVmFsLnNwbGl0KCcsJyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuT2JqW3FLZXldID0gcVZhbDtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuT2JqO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOb3JtYWxpemVzIGFuZCBtZXJnZXMgc3RyaW5ncyBvZiB0eXBlICdhPWInLCB7IGI6Y30gdG8geyBhOmIsIGI6Y31cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzMVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXMyXG4gICAgICAgICAqIEByZXR1cm4ge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIG1lcmdlUVM6IGZ1bmN0aW9uIChxczEsIHFzMikge1xuICAgICAgICAgICAgdmFyIG9iajEgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMSkpO1xuICAgICAgICAgICAgdmFyIG9iajIgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMikpO1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHt9LCBvYmoxLCBvYmoyKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhZGRUcmFpbGluZ1NsYXNoOiBmdW5jdGlvbiAodXJsKSB7XG4gICAgICAgICAgICBpZiAoIXVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAodXJsLmNoYXJBdCh1cmwubGVuZ3RoIC0gMSkgPT09ICcvJykgPyB1cmwgOiAodXJsICsgJy8nKTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuXG5cblxuIiwiLyoqXG4gKiBVdGlsaXRpZXMgZm9yIHdvcmtpbmcgd2l0aCB0aGUgcnVuIHNlcnZpY2VcbiovXG4ndXNlIHN0cmljdCc7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuL3F1ZXJ5LXV0aWwnKTtcbnZhciBNQVhfVVJMX0xFTkdUSCA9IDIwNDg7XG5cbm1vZHVsZS5leHBvcnRzID0gKGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICAvKipcbiAgICAgICAgICogcmV0dXJucyBvcGVyYXRpb25zIG9mIHRoZSBmb3JtIGBbW29wMSxvcDJdLCBbYXJnMSwgYXJnMl1dYFxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R8QXJyYXl8U3RyaW5nfSBgb3BlcmF0aW9uc2Agb3BlcmF0aW9ucyB0byBwZXJmb3JtXG4gICAgICAgICAqIEBwYXJhbSAge0FycmF5fSBgYXJnc2AgYXJndW1lbnRzIGZvciBvcGVyYXRpb25cbiAgICAgICAgICogQHJldHVybiB7U3RyaW5nfSAgICBNYXRyaXgtZm9ybWF0IHF1ZXJ5IHBhcmFtZXRlcnNcbiAgICAgICAgICovXG4gICAgICAgIG5vcm1hbGl6ZU9wZXJhdGlvbnM6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBhcmdzKSB7XG4gICAgICAgICAgICBpZiAoIWFyZ3MpIHtcbiAgICAgICAgICAgICAgICBhcmdzID0gW107XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgcmV0dXJuTGlzdCA9IHtcbiAgICAgICAgICAgICAgICBvcHM6IFtdLFxuICAgICAgICAgICAgICAgIGFyZ3M6IFtdXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX2NvbmNhdCA9IGZ1bmN0aW9uIChhcnIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKGFyciAhPT0gbnVsbCAmJiBhcnIgIT09IHVuZGVmaW5lZCkgPyBbXS5jb25jYXQoYXJyKSA6IFtdO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgLy97IGFkZDogWzEsMl0sIHN1YnRyYWN0OiBbMiw0XSB9XG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZVBsYWluT2JqZWN0cyA9IGZ1bmN0aW9uIChvcGVyYXRpb25zLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICQuZWFjaChvcGVyYXRpb25zLCBmdW5jdGlvbiAob3BuLCBhcmcpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcG4pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KGFyZykpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIC8veyBuYW1lOiAnYWRkJywgcGFyYW1zOiBbMV0gfVxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVTdHJ1Y3R1cmVkT2JqZWN0cyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcGVyYXRpb24ubmFtZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChvcGVyYXRpb24ucGFyYW1zKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZU9iamVjdCA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKChvcGVyYXRpb24ubmFtZSkgPyBfbm9ybWFsaXplU3RydWN0dXJlZE9iamVjdHMgOiBfbm9ybWFsaXplUGxhaW5PYmplY3RzKShvcGVyYXRpb24sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVMaXRlcmFscyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIGFyZ3MsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcGVyYXRpb24pO1xuICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQoYXJncykpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZUFycmF5cyA9IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBhcmcsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJC5lYWNoKG9wZXJhdGlvbnMsIGZ1bmN0aW9uIChpbmRleCwgb3BuKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qob3BuKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgX25vcm1hbGl6ZU9iamVjdChvcG4sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgX25vcm1hbGl6ZUxpdGVyYWxzKG9wbiwgYXJnc1tpbmRleF0sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KG9wZXJhdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZU9iamVjdChvcGVyYXRpb25zLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoJC5pc0FycmF5KG9wZXJhdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZUFycmF5cyhvcGVyYXRpb25zLCBhcmdzLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZUxpdGVyYWxzKG9wZXJhdGlvbnMsIGFyZ3MsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgfSxcblxuICAgICAgICBzcGxpdEdldEZhY3Rvcnk6IGZ1bmN0aW9uIChodHRwT3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICB2YXIgaHR0cCA9IHRoaXM7XG4gICAgICAgICAgICAgICAgdmFyIGdldFZhbHVlID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhbHVlID0gb3B0aW9uc1tuYW1lXSB8fCBodHRwT3B0aW9uc1tuYW1lXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciBnZXRGaW5hbFVybCA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybCA9IGdldFZhbHVlKCd1cmwnLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRhdGEgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZXJlIGlzIGVhc3kgKG9yIGtub3duKSB3YXkgdG8gZ2V0IHRoZSBmaW5hbCBVUkwganF1ZXJ5IGlzIGdvaW5nIHRvIHNlbmQgc29cbiAgICAgICAgICAgICAgICAgICAgLy8gd2UncmUgcmVwbGljYXRpbmcgaXQuIFRoZSBwcm9jZXNzIG1pZ2h0IGNoYW5nZSBhdCBzb21lIHBvaW50IGJ1dCBpdCBwcm9iYWJseSB3aWxsIG5vdC5cbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gUmVtb3ZlIGhhc2hcbiAgICAgICAgICAgICAgICAgICAgdXJsID0gdXJsLnJlcGxhY2UoLyMuKiQvLCAnJyk7XG4gICAgICAgICAgICAgICAgICAgIC8vIDEuIEFwcGVuZCBxdWVyeSBzdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXJ5UGFyYW1zID0gcXV0aWwudG9RdWVyeUZvcm1hdChkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXN0aW9uSWR4ID0gdXJsLmluZGV4T2YoJz8nKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHF1ZXJ5UGFyYW1zICYmIHF1ZXN0aW9uSWR4ID4gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmwgKyAnJicgKyBxdWVyeVBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChxdWVyeVBhcmFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybCArICc/JyArIHF1ZXJ5UGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmw7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgdXJsID0gZ2V0RmluYWxVcmwocGFyYW1zKTtcbiAgICAgICAgICAgICAgICAvLyBXZSBtdXN0IHNwbGl0IHRoZSBHRVQgaW4gbXVsdGlwbGUgc2hvcnQgVVJMJ3NcbiAgICAgICAgICAgICAgICAvLyBUaGUgb25seSBwcm9wZXJ0eSBhbGxvd2VkIHRvIGJlIHNwbGl0IGlzIFwiaW5jbHVkZVwiXG4gICAgICAgICAgICAgICAgaWYgKHBhcmFtcyAmJiBwYXJhbXMuaW5jbHVkZSAmJiB1cmwubGVuZ3RoID4gTUFYX1VSTF9MRU5HVEgpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmFtc0NvcHkgPSAkLmV4dGVuZCh0cnVlLCB7fSwgcGFyYW1zKTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHBhcmFtc0NvcHkuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybE5vSW5jbHVkZXMgPSBnZXRGaW5hbFVybChwYXJhbXNDb3B5KTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRpZmYgPSBNQVhfVVJMX0xFTkdUSCAtIHVybE5vSW5jbHVkZXMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IG9wdGlvbnMuc3VjY2VzcyB8fCBodHRwT3B0aW9ucy5zdWNjZXNzIHx8ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZEVycm9yID0gb3B0aW9ucy5lcnJvciB8fCBodHRwT3B0aW9ucy5lcnJvciB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSB0aGUgb3JpZ2luYWwgc3VjY2VzcyBhbmQgZXJyb3IgY2FsbGJhY2tzXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuc3VjY2VzcyA9ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvciA9ICQubm9vcDtcblxuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZSA9IHBhcmFtcy5pbmNsdWRlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VyckluY2x1ZGVzID0gW107XG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmNsdWRlT3B0cyA9IFtjdXJySW5jbHVkZXNdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHZhcmlhYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgYSBncmVlZHkgYXBwcm9hY2ggZm9yIG5vdywgY2FuIGJlIG9wdGltaXplZCB0byBiZSBzb2x2ZWQgaW4gYSBtb3JlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBlZmZpY2llbnQgd2F5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyArIDEgaXMgdGhlIGNvbW1hXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3Vyckxlbmd0aCArIHZhcmlhYmxlLmxlbmd0aCArIDEgPCBkaWZmKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzLnB1c2godmFyaWFibGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJMZW5ndGggKz0gdmFyaWFibGUubGVuZ3RoICsgMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzID0gW3ZhcmlhYmxlXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlT3B0cy5wdXNoKGN1cnJJbmNsdWRlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aCArIHZhcmlhYmxlLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB2YXIgcmVxcyA9ICQubWFwKGluY2x1ZGVPcHRzLCBmdW5jdGlvbiAoaW5jbHVkZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlcVBhcmFtcyA9ICQuZXh0ZW5kKHt9LCBwYXJhbXMsIHsgaW5jbHVkZTogaW5jbHVkZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChyZXFQYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgJC53aGVuLmFwcGx5KCQsIHJlcXMpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRWFjaCBhcmd1bWVudCBhcmUgYXJyYXlzIG9mIHRoZSBhcmd1bWVudHMgb2YgZWFjaCBkb25lIHJlcXVlc3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgZmlyc3QgYXJyYXkgb2YgYXJndW1lbnRzIGlzIHRoZSBkYXRhXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNWYWxpZCA9IGFyZ3VtZW50c1swXSAmJiBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaG91bGQgbmV2ZXIgaGFwcGVuLi4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpcnN0UmVzcG9uc2UgPSBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNSdW5BUEkgPSAoaXNPYmplY3QgJiYgJC5pc1BsYWluT2JqZWN0KGZpcnN0UmVzcG9uc2UudmFyaWFibGVzKSkgfHwgIWlzT2JqZWN0O1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzUnVuQVBJKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzT2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnZ3JlZ2F0ZSB0aGUgdmFyaWFibGVzIHByb3BlcnR5IG9ubHlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZVJ1biA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJ1biA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVSdW4udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZVJ1biwgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFycmF5IG9mIHJ1bnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWdyZWdhdGUgdmFyaWFibGVzIGluIGVhY2ggcnVuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkUnVucyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVucyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISQuaXNBcnJheShydW5zKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChydW5zLCBmdW5jdGlvbiAoaWR4UnVuLCBydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocnVuLmlkICYmICFhZ2dyZWdhdGVkUnVuc1tydW4uaWRdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bi52YXJpYWJsZXMgPSBydW4udmFyaWFibGVzIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVuc1tydW4uaWRdID0gcnVuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocnVuLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHR1cm4gaXQgaW50byBhbiBhcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVucyA9ICQubWFwKGFnZ3JlZ2F0ZWRSdW5zLCBmdW5jdGlvbiAocnVuKSB7IHJldHVybiBydW47IH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyB2YXJpYWJsZXMgQVBJXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSByZXNwb25zZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkVmFyaWFibGVzID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFycyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIHZhcnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IuYXBwbHkoaHR0cCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZWplY3QuYXBwbHkoZHRkLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuIl19 +//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL25vZGVfbW9kdWxlcy9pZWVlNzU0L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvaXMtYXJyYXkvaW5kZXguanMiLCJzcmMvYXBpLXZlcnNpb24uanNvbiIsInNyYy9hcHAuanMiLCJzcmMvbWFuYWdlcnMvYXV0aC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2NoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2tleS1uYW1lcy5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9hbHdheXMtbmV3LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2lkZW50aXR5LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL211bHRpcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcC5qcyIsInNyYy9tYW5hZ2Vycy9zY2VuYXJpby1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3NwZWNpYWwtb3BlcmF0aW9ucy5qcyIsInNyYy9tYW5hZ2Vycy93b3JsZC1tYW5hZ2VyLmpzIiwic3JjL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyLmpzIiwic3JjL3N0b3JlL2Nvb2tpZS1zdG9yZS5qcyIsInNyYy9zdG9yZS9zdG9yZS1mYWN0b3J5LmpzIiwic3JjL3RyYW5zcG9ydC9hamF4LWh0dHAtdHJhbnNwb3J0LmpzIiwic3JjL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5LmpzIiwic3JjL3V0aWwvaW5oZXJpdC5qcyIsInNyYy91dGlsL21ha2Utc2VxdWVuY2UuanMiLCJzcmMvdXRpbC9vYmplY3QtdXRpbC5qcyIsInNyYy91dGlsL3F1ZXJ5LXV0aWwuanMiLCJzcmMvdXRpbC9ydW4tdXRpbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN4Z0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNVdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6T0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdFFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4ZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6SkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM3VCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8qIVxuICogVGhlIGJ1ZmZlciBtb2R1bGUgZnJvbSBub2RlLmpzLCBmb3IgdGhlIGJyb3dzZXIuXG4gKlxuICogQGF1dGhvciAgIEZlcm9zcyBBYm91a2hhZGlqZWggPGZlcm9zc0BmZXJvc3Mub3JnPiA8aHR0cDovL2Zlcm9zcy5vcmc+XG4gKiBAbGljZW5zZSAgTUlUXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIG5vLXByb3RvICovXG5cbnZhciBiYXNlNjQgPSByZXF1aXJlKCdiYXNlNjQtanMnKVxudmFyIGllZWU3NTQgPSByZXF1aXJlKCdpZWVlNzU0JylcbnZhciBpc0FycmF5ID0gcmVxdWlyZSgnaXMtYXJyYXknKVxuXG5leHBvcnRzLkJ1ZmZlciA9IEJ1ZmZlclxuZXhwb3J0cy5TbG93QnVmZmVyID0gU2xvd0J1ZmZlclxuZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFUyA9IDUwXG5CdWZmZXIucG9vbFNpemUgPSA4MTkyIC8vIG5vdCB1c2VkIGJ5IHRoaXMgaW1wbGVtZW50YXRpb25cblxudmFyIHJvb3RQYXJlbnQgPSB7fVxuXG4vKipcbiAqIElmIGBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVGA6XG4gKiAgID09PSB0cnVlICAgIFVzZSBVaW50OEFycmF5IGltcGxlbWVudGF0aW9uIChmYXN0ZXN0KVxuICogICA9PT0gZmFsc2UgICBVc2UgT2JqZWN0IGltcGxlbWVudGF0aW9uIChtb3N0IGNvbXBhdGlibGUsIGV2ZW4gSUU2KVxuICpcbiAqIEJyb3dzZXJzIHRoYXQgc3VwcG9ydCB0eXBlZCBhcnJheXMgYXJlIElFIDEwKywgRmlyZWZveCA0KywgQ2hyb21lIDcrLCBTYWZhcmkgNS4xKyxcbiAqIE9wZXJhIDExLjYrLCBpT1MgNC4yKy5cbiAqXG4gKiBEdWUgdG8gdmFyaW91cyBicm93c2VyIGJ1Z3MsIHNvbWV0aW1lcyB0aGUgT2JqZWN0IGltcGxlbWVudGF0aW9uIHdpbGwgYmUgdXNlZCBldmVuXG4gKiB3aGVuIHRoZSBicm93c2VyIHN1cHBvcnRzIHR5cGVkIGFycmF5cy5cbiAqXG4gKiBOb3RlOlxuICpcbiAqICAgLSBGaXJlZm94IDQtMjkgbGFja3Mgc3VwcG9ydCBmb3IgYWRkaW5nIG5ldyBwcm9wZXJ0aWVzIHRvIGBVaW50OEFycmF5YCBpbnN0YW5jZXMsXG4gKiAgICAgU2VlOiBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD02OTU0MzguXG4gKlxuICogICAtIFNhZmFyaSA1LTcgbGFja3Mgc3VwcG9ydCBmb3IgY2hhbmdpbmcgdGhlIGBPYmplY3QucHJvdG90eXBlLmNvbnN0cnVjdG9yYCBwcm9wZXJ0eVxuICogICAgIG9uIG9iamVjdHMuXG4gKlxuICogICAtIENocm9tZSA5LTEwIGlzIG1pc3NpbmcgdGhlIGBUeXBlZEFycmF5LnByb3RvdHlwZS5zdWJhcnJheWAgZnVuY3Rpb24uXG4gKlxuICogICAtIElFMTAgaGFzIGEgYnJva2VuIGBUeXBlZEFycmF5LnByb3RvdHlwZS5zdWJhcnJheWAgZnVuY3Rpb24gd2hpY2ggcmV0dXJucyBhcnJheXMgb2ZcbiAqICAgICBpbmNvcnJlY3QgbGVuZ3RoIGluIHNvbWUgc2l0dWF0aW9ucy5cblxuICogV2UgZGV0ZWN0IHRoZXNlIGJ1Z2d5IGJyb3dzZXJzIGFuZCBzZXQgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYCB0byBgZmFsc2VgIHNvIHRoZXlcbiAqIGdldCB0aGUgT2JqZWN0IGltcGxlbWVudGF0aW9uLCB3aGljaCBpcyBzbG93ZXIgYnV0IGJlaGF2ZXMgY29ycmVjdGx5LlxuICovXG5CdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCA9IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUICE9PSB1bmRlZmluZWRcbiAgPyBnbG9iYWwuVFlQRURfQVJSQVlfU1VQUE9SVFxuICA6IHR5cGVkQXJyYXlTdXBwb3J0KClcblxuZnVuY3Rpb24gdHlwZWRBcnJheVN1cHBvcnQgKCkge1xuICBmdW5jdGlvbiBCYXIgKCkge31cbiAgdHJ5IHtcbiAgICB2YXIgYXJyID0gbmV3IFVpbnQ4QXJyYXkoMSlcbiAgICBhcnIuZm9vID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gNDIgfVxuICAgIGFyci5jb25zdHJ1Y3RvciA9IEJhclxuICAgIHJldHVybiBhcnIuZm9vKCkgPT09IDQyICYmIC8vIHR5cGVkIGFycmF5IGluc3RhbmNlcyBjYW4gYmUgYXVnbWVudGVkXG4gICAgICAgIGFyci5jb25zdHJ1Y3RvciA9PT0gQmFyICYmIC8vIGNvbnN0cnVjdG9yIGNhbiBiZSBzZXRcbiAgICAgICAgdHlwZW9mIGFyci5zdWJhcnJheSA9PT0gJ2Z1bmN0aW9uJyAmJiAvLyBjaHJvbWUgOS0xMCBsYWNrIGBzdWJhcnJheWBcbiAgICAgICAgYXJyLnN1YmFycmF5KDEsIDEpLmJ5dGVMZW5ndGggPT09IDAgLy8gaWUxMCBoYXMgYnJva2VuIGBzdWJhcnJheWBcbiAgfSBjYXRjaCAoZSkge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbmZ1bmN0aW9uIGtNYXhMZW5ndGggKCkge1xuICByZXR1cm4gQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRcbiAgICA/IDB4N2ZmZmZmZmZcbiAgICA6IDB4M2ZmZmZmZmZcbn1cblxuLyoqXG4gKiBDbGFzczogQnVmZmVyXG4gKiA9PT09PT09PT09PT09XG4gKlxuICogVGhlIEJ1ZmZlciBjb25zdHJ1Y3RvciByZXR1cm5zIGluc3RhbmNlcyBvZiBgVWludDhBcnJheWAgdGhhdCBhcmUgYXVnbWVudGVkXG4gKiB3aXRoIGZ1bmN0aW9uIHByb3BlcnRpZXMgZm9yIGFsbCB0aGUgbm9kZSBgQnVmZmVyYCBBUEkgZnVuY3Rpb25zLiBXZSB1c2VcbiAqIGBVaW50OEFycmF5YCBzbyB0aGF0IHNxdWFyZSBicmFja2V0IG5vdGF0aW9uIHdvcmtzIGFzIGV4cGVjdGVkIC0tIGl0IHJldHVybnNcbiAqIGEgc2luZ2xlIG9jdGV0LlxuICpcbiAqIEJ5IGF1Z21lbnRpbmcgdGhlIGluc3RhbmNlcywgd2UgY2FuIGF2b2lkIG1vZGlmeWluZyB0aGUgYFVpbnQ4QXJyYXlgXG4gKiBwcm90b3R5cGUuXG4gKi9cbmZ1bmN0aW9uIEJ1ZmZlciAoYXJnKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBCdWZmZXIpKSB7XG4gICAgLy8gQXZvaWQgZ29pbmcgdGhyb3VnaCBhbiBBcmd1bWVudHNBZGFwdG9yVHJhbXBvbGluZSBpbiB0aGUgY29tbW9uIGNhc2UuXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSByZXR1cm4gbmV3IEJ1ZmZlcihhcmcsIGFyZ3VtZW50c1sxXSlcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcihhcmcpXG4gIH1cblxuICB0aGlzLmxlbmd0aCA9IDBcbiAgdGhpcy5wYXJlbnQgPSB1bmRlZmluZWRcblxuICAvLyBDb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdudW1iZXInKSB7XG4gICAgcmV0dXJuIGZyb21OdW1iZXIodGhpcywgYXJnKVxuICB9XG5cbiAgLy8gU2xpZ2h0bHkgbGVzcyBjb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIGZyb21TdHJpbmcodGhpcywgYXJnLCBhcmd1bWVudHMubGVuZ3RoID4gMSA/IGFyZ3VtZW50c1sxXSA6ICd1dGY4JylcbiAgfVxuXG4gIC8vIFVudXN1YWwuXG4gIHJldHVybiBmcm9tT2JqZWN0KHRoaXMsIGFyZylcbn1cblxuZnVuY3Rpb24gZnJvbU51bWJlciAodGhhdCwgbGVuZ3RoKSB7XG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGggPCAwID8gMCA6IGNoZWNrZWQobGVuZ3RoKSB8IDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICB0aGF0W2ldID0gMFxuICAgIH1cbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tU3RyaW5nICh0aGF0LCBzdHJpbmcsIGVuY29kaW5nKSB7XG4gIGlmICh0eXBlb2YgZW5jb2RpbmcgIT09ICdzdHJpbmcnIHx8IGVuY29kaW5nID09PSAnJykgZW5jb2RpbmcgPSAndXRmOCdcblxuICAvLyBBc3N1bXB0aW9uOiBieXRlTGVuZ3RoKCkgcmV0dXJuIHZhbHVlIGlzIGFsd2F5cyA8IGtNYXhMZW5ndGguXG4gIHZhciBsZW5ndGggPSBieXRlTGVuZ3RoKHN0cmluZywgZW5jb2RpbmcpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuXG4gIHRoYXQud3JpdGUoc3RyaW5nLCBlbmNvZGluZylcbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbU9iamVjdCAodGhhdCwgb2JqZWN0KSB7XG4gIGlmIChCdWZmZXIuaXNCdWZmZXIob2JqZWN0KSkgcmV0dXJuIGZyb21CdWZmZXIodGhhdCwgb2JqZWN0KVxuXG4gIGlmIChpc0FycmF5KG9iamVjdCkpIHJldHVybiBmcm9tQXJyYXkodGhhdCwgb2JqZWN0KVxuXG4gIGlmIChvYmplY3QgPT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ211c3Qgc3RhcnQgd2l0aCBudW1iZXIsIGJ1ZmZlciwgYXJyYXkgb3Igc3RyaW5nJylcbiAgfVxuXG4gIGlmICh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgaWYgKG9iamVjdC5idWZmZXIgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikge1xuICAgICAgcmV0dXJuIGZyb21UeXBlZEFycmF5KHRoYXQsIG9iamVjdClcbiAgICB9XG4gICAgaWYgKG9iamVjdCBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgICByZXR1cm4gZnJvbUFycmF5QnVmZmVyKHRoYXQsIG9iamVjdClcbiAgICB9XG4gIH1cblxuICBpZiAob2JqZWN0Lmxlbmd0aCkgcmV0dXJuIGZyb21BcnJheUxpa2UodGhhdCwgb2JqZWN0KVxuXG4gIHJldHVybiBmcm9tSnNvbk9iamVjdCh0aGF0LCBvYmplY3QpXG59XG5cbmZ1bmN0aW9uIGZyb21CdWZmZXIgKHRoYXQsIGJ1ZmZlcikge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChidWZmZXIubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcbiAgYnVmZmVyLmNvcHkodGhhdCwgMCwgMCwgbGVuZ3RoKVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXkgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vLyBEdXBsaWNhdGUgb2YgZnJvbUFycmF5KCkgdG8ga2VlcCBmcm9tQXJyYXkoKSBtb25vbW9ycGhpYy5cbmZ1bmN0aW9uIGZyb21UeXBlZEFycmF5ICh0aGF0LCBhcnJheSkge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICAvLyBUcnVuY2F0aW5nIHRoZSBlbGVtZW50cyBpcyBwcm9iYWJseSBub3Qgd2hhdCBwZW9wbGUgZXhwZWN0IGZyb20gdHlwZWRcbiAgLy8gYXJyYXlzIHdpdGggQllURVNfUEVSX0VMRU1FTlQgPiAxIGJ1dCBpdCdzIGNvbXBhdGlibGUgd2l0aCB0aGUgYmVoYXZpb3JcbiAgLy8gb2YgdGhlIG9sZCBCdWZmZXIgY29uc3RydWN0b3IuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlCdWZmZXIgKHRoYXQsIGFycmF5KSB7XG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIFJldHVybiBhbiBhdWdtZW50ZWQgYFVpbnQ4QXJyYXlgIGluc3RhbmNlLCBmb3IgYmVzdCBwZXJmb3JtYW5jZVxuICAgIGFycmF5LmJ5dGVMZW5ndGhcbiAgICB0aGF0ID0gQnVmZmVyLl9hdWdtZW50KG5ldyBVaW50OEFycmF5KGFycmF5KSlcbiAgfSBlbHNlIHtcbiAgICAvLyBGYWxsYmFjazogUmV0dXJuIGFuIG9iamVjdCBpbnN0YW5jZSBvZiB0aGUgQnVmZmVyIGNsYXNzXG4gICAgdGhhdCA9IGZyb21UeXBlZEFycmF5KHRoYXQsIG5ldyBVaW50OEFycmF5KGFycmF5KSlcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlMaWtlICh0aGF0LCBhcnJheSkge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuLy8gRGVzZXJpYWxpemUgeyB0eXBlOiAnQnVmZmVyJywgZGF0YTogWzEsMiwzLC4uLl0gfSBpbnRvIGEgQnVmZmVyIG9iamVjdC5cbi8vIFJldHVybnMgYSB6ZXJvLWxlbmd0aCBidWZmZXIgZm9yIGlucHV0cyB0aGF0IGRvbid0IGNvbmZvcm0gdG8gdGhlIHNwZWMuXG5mdW5jdGlvbiBmcm9tSnNvbk9iamVjdCAodGhhdCwgb2JqZWN0KSB7XG4gIHZhciBhcnJheVxuICB2YXIgbGVuZ3RoID0gMFxuXG4gIGlmIChvYmplY3QudHlwZSA9PT0gJ0J1ZmZlcicgJiYgaXNBcnJheShvYmplY3QuZGF0YSkpIHtcbiAgICBhcnJheSA9IG9iamVjdC5kYXRhXG4gICAgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB9XG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICBCdWZmZXIucHJvdG90eXBlLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXkucHJvdG90eXBlXG4gIEJ1ZmZlci5fX3Byb3RvX18gPSBVaW50OEFycmF5XG59XG5cbmZ1bmN0aW9uIGFsbG9jYXRlICh0aGF0LCBsZW5ndGgpIHtcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgdGhhdCA9IEJ1ZmZlci5fYXVnbWVudChuZXcgVWludDhBcnJheShsZW5ndGgpKVxuICAgIHRoYXQuX19wcm90b19fID0gQnVmZmVyLnByb3RvdHlwZVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0Lmxlbmd0aCA9IGxlbmd0aFxuICAgIHRoYXQuX2lzQnVmZmVyID0gdHJ1ZVxuICB9XG5cbiAgdmFyIGZyb21Qb29sID0gbGVuZ3RoICE9PSAwICYmIGxlbmd0aCA8PSBCdWZmZXIucG9vbFNpemUgPj4+IDFcbiAgaWYgKGZyb21Qb29sKSB0aGF0LnBhcmVudCA9IHJvb3RQYXJlbnRcblxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBjaGVja2VkIChsZW5ndGgpIHtcbiAgLy8gTm90ZTogY2Fubm90IHVzZSBgbGVuZ3RoIDwga01heExlbmd0aGAgaGVyZSBiZWNhdXNlIHRoYXQgZmFpbHMgd2hlblxuICAvLyBsZW5ndGggaXMgTmFOICh3aGljaCBpcyBvdGhlcndpc2UgY29lcmNlZCB0byB6ZXJvLilcbiAgaWYgKGxlbmd0aCA+PSBrTWF4TGVuZ3RoKCkpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignQXR0ZW1wdCB0byBhbGxvY2F0ZSBCdWZmZXIgbGFyZ2VyIHRoYW4gbWF4aW11bSAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAnc2l6ZTogMHgnICsga01heExlbmd0aCgpLnRvU3RyaW5nKDE2KSArICcgYnl0ZXMnKVxuICB9XG4gIHJldHVybiBsZW5ndGggfCAwXG59XG5cbmZ1bmN0aW9uIFNsb3dCdWZmZXIgKHN1YmplY3QsIGVuY29kaW5nKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBTbG93QnVmZmVyKSkgcmV0dXJuIG5ldyBTbG93QnVmZmVyKHN1YmplY3QsIGVuY29kaW5nKVxuXG4gIHZhciBidWYgPSBuZXcgQnVmZmVyKHN1YmplY3QsIGVuY29kaW5nKVxuICBkZWxldGUgYnVmLnBhcmVudFxuICByZXR1cm4gYnVmXG59XG5cbkJ1ZmZlci5pc0J1ZmZlciA9IGZ1bmN0aW9uIGlzQnVmZmVyIChiKSB7XG4gIHJldHVybiAhIShiICE9IG51bGwgJiYgYi5faXNCdWZmZXIpXG59XG5cbkJ1ZmZlci5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYSwgYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihhKSB8fCAhQnVmZmVyLmlzQnVmZmVyKGIpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnRzIG11c3QgYmUgQnVmZmVycycpXG4gIH1cblxuICBpZiAoYSA9PT0gYikgcmV0dXJuIDBcblxuICB2YXIgeCA9IGEubGVuZ3RoXG4gIHZhciB5ID0gYi5sZW5ndGhcblxuICB2YXIgaSA9IDBcbiAgdmFyIGxlbiA9IE1hdGgubWluKHgsIHkpXG4gIHdoaWxlIChpIDwgbGVuKSB7XG4gICAgaWYgKGFbaV0gIT09IGJbaV0pIGJyZWFrXG5cbiAgICArK2lcbiAgfVxuXG4gIGlmIChpICE9PSBsZW4pIHtcbiAgICB4ID0gYVtpXVxuICAgIHkgPSBiW2ldXG4gIH1cblxuICBpZiAoeCA8IHkpIHJldHVybiAtMVxuICBpZiAoeSA8IHgpIHJldHVybiAxXG4gIHJldHVybiAwXG59XG5cbkJ1ZmZlci5pc0VuY29kaW5nID0gZnVuY3Rpb24gaXNFbmNvZGluZyAoZW5jb2RpbmcpIHtcbiAgc3dpdGNoIChTdHJpbmcoZW5jb2RpbmcpLnRvTG93ZXJDYXNlKCkpIHtcbiAgICBjYXNlICdoZXgnOlxuICAgIGNhc2UgJ3V0ZjgnOlxuICAgIGNhc2UgJ3V0Zi04JzpcbiAgICBjYXNlICdhc2NpaSc6XG4gICAgY2FzZSAnYmluYXJ5JzpcbiAgICBjYXNlICdiYXNlNjQnOlxuICAgIGNhc2UgJ3Jhdyc6XG4gICAgY2FzZSAndWNzMic6XG4gICAgY2FzZSAndWNzLTInOlxuICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgIHJldHVybiB0cnVlXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbkJ1ZmZlci5jb25jYXQgPSBmdW5jdGlvbiBjb25jYXQgKGxpc3QsIGxlbmd0aCkge1xuICBpZiAoIWlzQXJyYXkobGlzdCkpIHRocm93IG5ldyBUeXBlRXJyb3IoJ2xpc3QgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzLicpXG5cbiAgaWYgKGxpc3QubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIG5ldyBCdWZmZXIoMClcbiAgfVxuXG4gIHZhciBpXG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCkge1xuICAgIGxlbmd0aCA9IDBcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykge1xuICAgICAgbGVuZ3RoICs9IGxpc3RbaV0ubGVuZ3RoXG4gICAgfVxuICB9XG5cbiAgdmFyIGJ1ZiA9IG5ldyBCdWZmZXIobGVuZ3RoKVxuICB2YXIgcG9zID0gMFxuICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykge1xuICAgIHZhciBpdGVtID0gbGlzdFtpXVxuICAgIGl0ZW0uY29weShidWYsIHBvcylcbiAgICBwb3MgKz0gaXRlbS5sZW5ndGhcbiAgfVxuICByZXR1cm4gYnVmXG59XG5cbmZ1bmN0aW9uIGJ5dGVMZW5ndGggKHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBzdHJpbmcgIT09ICdzdHJpbmcnKSBzdHJpbmcgPSAnJyArIHN0cmluZ1xuXG4gIHZhciBsZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChsZW4gPT09IDApIHJldHVybiAwXG5cbiAgLy8gVXNlIGEgZm9yIGxvb3AgdG8gYXZvaWQgcmVjdXJzaW9uXG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG4gIGZvciAoOzspIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgLy8gRGVwcmVjYXRlZFxuICAgICAgY2FzZSAncmF3JzpcbiAgICAgIGNhc2UgJ3Jhd3MnOlxuICAgICAgICByZXR1cm4gbGVuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhUb0J5dGVzKHN0cmluZykubGVuZ3RoXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gbGVuICogMlxuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGxlbiA+Pj4gMVxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGhcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgcmV0dXJuIHV0ZjhUb0J5dGVzKHN0cmluZykubGVuZ3RoIC8vIGFzc3VtZSB1dGY4XG4gICAgICAgIGVuY29kaW5nID0gKCcnICsgZW5jb2RpbmcpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5CdWZmZXIuYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGhcblxuLy8gcHJlLXNldCBmb3IgdmFsdWVzIHRoYXQgbWF5IGV4aXN0IGluIHRoZSBmdXR1cmVcbkJ1ZmZlci5wcm90b3R5cGUubGVuZ3RoID0gdW5kZWZpbmVkXG5CdWZmZXIucHJvdG90eXBlLnBhcmVudCA9IHVuZGVmaW5lZFxuXG5mdW5jdGlvbiBzbG93VG9TdHJpbmcgKGVuY29kaW5nLCBzdGFydCwgZW5kKSB7XG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG5cbiAgc3RhcnQgPSBzdGFydCB8IDBcbiAgZW5kID0gZW5kID09PSB1bmRlZmluZWQgfHwgZW5kID09PSBJbmZpbml0eSA/IHRoaXMubGVuZ3RoIDogZW5kIHwgMFxuXG4gIGlmICghZW5jb2RpbmcpIGVuY29kaW5nID0gJ3V0ZjgnXG4gIGlmIChzdGFydCA8IDApIHN0YXJ0ID0gMFxuICBpZiAoZW5kID4gdGhpcy5sZW5ndGgpIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmIChlbmQgPD0gc3RhcnQpIHJldHVybiAnJ1xuXG4gIHdoaWxlICh0cnVlKSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGhleFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgICAgcmV0dXJuIGFzY2lpU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgICAgcmV0dXJuIGJpbmFyeVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIHJldHVybiBiYXNlNjRTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gdXRmMTZsZVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgICAgICBlbmNvZGluZyA9IChlbmNvZGluZyArICcnKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gdG9TdHJpbmcgKCkge1xuICB2YXIgbGVuZ3RoID0gdGhpcy5sZW5ndGggfCAwXG4gIGlmIChsZW5ndGggPT09IDApIHJldHVybiAnJ1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCAwLCBsZW5ndGgpXG4gIHJldHVybiBzbG93VG9TdHJpbmcuYXBwbHkodGhpcywgYXJndW1lbnRzKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uIGVxdWFscyAoYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpXG4gIGlmICh0aGlzID09PSBiKSByZXR1cm4gdHJ1ZVxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYikgPT09IDBcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbnNwZWN0ID0gZnVuY3Rpb24gaW5zcGVjdCAoKSB7XG4gIHZhciBzdHIgPSAnJ1xuICB2YXIgbWF4ID0gZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFU1xuICBpZiAodGhpcy5sZW5ndGggPiAwKSB7XG4gICAgc3RyID0gdGhpcy50b1N0cmluZygnaGV4JywgMCwgbWF4KS5tYXRjaCgvLnsyfS9nKS5qb2luKCcgJylcbiAgICBpZiAodGhpcy5sZW5ndGggPiBtYXgpIHN0ciArPSAnIC4uLiAnXG4gIH1cbiAgcmV0dXJuICc8QnVmZmVyICcgKyBzdHIgKyAnPidcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpXG4gIGlmICh0aGlzID09PSBiKSByZXR1cm4gMFxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYilcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbmRleE9mID0gZnVuY3Rpb24gaW5kZXhPZiAodmFsLCBieXRlT2Zmc2V0KSB7XG4gIGlmIChieXRlT2Zmc2V0ID4gMHg3ZmZmZmZmZikgYnl0ZU9mZnNldCA9IDB4N2ZmZmZmZmZcbiAgZWxzZSBpZiAoYnl0ZU9mZnNldCA8IC0weDgwMDAwMDAwKSBieXRlT2Zmc2V0ID0gLTB4ODAwMDAwMDBcbiAgYnl0ZU9mZnNldCA+Pj0gMFxuXG4gIGlmICh0aGlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xXG4gIGlmIChieXRlT2Zmc2V0ID49IHRoaXMubGVuZ3RoKSByZXR1cm4gLTFcblxuICAvLyBOZWdhdGl2ZSBvZmZzZXRzIHN0YXJ0IGZyb20gdGhlIGVuZCBvZiB0aGUgYnVmZmVyXG4gIGlmIChieXRlT2Zmc2V0IDwgMCkgYnl0ZU9mZnNldCA9IE1hdGgubWF4KHRoaXMubGVuZ3RoICsgYnl0ZU9mZnNldCwgMClcblxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICBpZiAodmFsLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xIC8vIHNwZWNpYWwgY2FzZTogbG9va2luZyBmb3IgZW1wdHkgc3RyaW5nIGFsd2F5cyBmYWlsc1xuICAgIHJldHVybiBTdHJpbmcucHJvdG90eXBlLmluZGV4T2YuY2FsbCh0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gIH1cbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcih2YWwpKSB7XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gIH1cbiAgaWYgKHR5cGVvZiB2YWwgPT09ICdudW1iZXInKSB7XG4gICAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUICYmIFVpbnQ4QXJyYXkucHJvdG90eXBlLmluZGV4T2YgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHJldHVybiBVaW50OEFycmF5LnByb3RvdHlwZS5pbmRleE9mLmNhbGwodGhpcywgdmFsLCBieXRlT2Zmc2V0KVxuICAgIH1cbiAgICByZXR1cm4gYXJyYXlJbmRleE9mKHRoaXMsIFsgdmFsIF0sIGJ5dGVPZmZzZXQpXG4gIH1cblxuICBmdW5jdGlvbiBhcnJheUluZGV4T2YgKGFyciwgdmFsLCBieXRlT2Zmc2V0KSB7XG4gICAgdmFyIGZvdW5kSW5kZXggPSAtMVxuICAgIGZvciAodmFyIGkgPSAwOyBieXRlT2Zmc2V0ICsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGFycltieXRlT2Zmc2V0ICsgaV0gPT09IHZhbFtmb3VuZEluZGV4ID09PSAtMSA/IDAgOiBpIC0gZm91bmRJbmRleF0pIHtcbiAgICAgICAgaWYgKGZvdW5kSW5kZXggPT09IC0xKSBmb3VuZEluZGV4ID0gaVxuICAgICAgICBpZiAoaSAtIGZvdW5kSW5kZXggKyAxID09PSB2YWwubGVuZ3RoKSByZXR1cm4gYnl0ZU9mZnNldCArIGZvdW5kSW5kZXhcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvdW5kSW5kZXggPSAtMVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gLTFcbiAgfVxuXG4gIHRocm93IG5ldyBUeXBlRXJyb3IoJ3ZhbCBtdXN0IGJlIHN0cmluZywgbnVtYmVyIG9yIEJ1ZmZlcicpXG59XG5cbi8vIGBnZXRgIGlzIGRlcHJlY2F0ZWRcbkJ1ZmZlci5wcm90b3R5cGUuZ2V0ID0gZnVuY3Rpb24gZ2V0IChvZmZzZXQpIHtcbiAgY29uc29sZS5sb2coJy5nZXQoKSBpcyBkZXByZWNhdGVkLiBBY2Nlc3MgdXNpbmcgYXJyYXkgaW5kZXhlcyBpbnN0ZWFkLicpXG4gIHJldHVybiB0aGlzLnJlYWRVSW50OChvZmZzZXQpXG59XG5cbi8vIGBzZXRgIGlzIGRlcHJlY2F0ZWRcbkJ1ZmZlci5wcm90b3R5cGUuc2V0ID0gZnVuY3Rpb24gc2V0ICh2LCBvZmZzZXQpIHtcbiAgY29uc29sZS5sb2coJy5zZXQoKSBpcyBkZXByZWNhdGVkLiBBY2Nlc3MgdXNpbmcgYXJyYXkgaW5kZXhlcyBpbnN0ZWFkLicpXG4gIHJldHVybiB0aGlzLndyaXRlVUludDgodiwgb2Zmc2V0KVxufVxuXG5mdW5jdGlvbiBoZXhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIG9mZnNldCA9IE51bWJlcihvZmZzZXQpIHx8IDBcbiAgdmFyIHJlbWFpbmluZyA9IGJ1Zi5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKCFsZW5ndGgpIHtcbiAgICBsZW5ndGggPSByZW1haW5pbmdcbiAgfSBlbHNlIHtcbiAgICBsZW5ndGggPSBOdW1iZXIobGVuZ3RoKVxuICAgIGlmIChsZW5ndGggPiByZW1haW5pbmcpIHtcbiAgICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICAgIH1cbiAgfVxuXG4gIC8vIG11c3QgYmUgYW4gZXZlbiBudW1iZXIgb2YgZGlnaXRzXG4gIHZhciBzdHJMZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChzdHJMZW4gJSAyICE9PSAwKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGV4IHN0cmluZycpXG5cbiAgaWYgKGxlbmd0aCA+IHN0ckxlbiAvIDIpIHtcbiAgICBsZW5ndGggPSBzdHJMZW4gLyAyXG4gIH1cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIHZhciBwYXJzZWQgPSBwYXJzZUludChzdHJpbmcuc3Vic3RyKGkgKiAyLCAyKSwgMTYpXG4gICAgaWYgKGlzTmFOKHBhcnNlZCkpIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSBwYXJzZWRcbiAgfVxuICByZXR1cm4gaVxufVxuXG5mdW5jdGlvbiB1dGY4V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcih1dGY4VG9CeXRlcyhzdHJpbmcsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBhc2NpaVdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIoYXNjaWlUb0J5dGVzKHN0cmluZyksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGJpbmFyeVdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGFzY2lpV3JpdGUoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBiYXNlNjRXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKGJhc2U2NFRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gdWNzMldyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIodXRmMTZsZVRvQnl0ZXMoc3RyaW5nLCBidWYubGVuZ3RoIC0gb2Zmc2V0KSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZSA9IGZ1bmN0aW9uIHdyaXRlIChzdHJpbmcsIG9mZnNldCwgbGVuZ3RoLCBlbmNvZGluZykge1xuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nKVxuICBpZiAob2Zmc2V0ID09PSB1bmRlZmluZWQpIHtcbiAgICBlbmNvZGluZyA9ICd1dGY4J1xuICAgIGxlbmd0aCA9IHRoaXMubGVuZ3RoXG4gICAgb2Zmc2V0ID0gMFxuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nLCBlbmNvZGluZylcbiAgfSBlbHNlIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygb2Zmc2V0ID09PSAnc3RyaW5nJykge1xuICAgIGVuY29kaW5nID0gb2Zmc2V0XG4gICAgbGVuZ3RoID0gdGhpcy5sZW5ndGhcbiAgICBvZmZzZXQgPSAwXG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcsIG9mZnNldFssIGxlbmd0aF1bLCBlbmNvZGluZ10pXG4gIH0gZWxzZSBpZiAoaXNGaW5pdGUob2Zmc2V0KSkge1xuICAgIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgICBpZiAoaXNGaW5pdGUobGVuZ3RoKSkge1xuICAgICAgbGVuZ3RoID0gbGVuZ3RoIHwgMFxuICAgICAgaWYgKGVuY29kaW5nID09PSB1bmRlZmluZWQpIGVuY29kaW5nID0gJ3V0ZjgnXG4gICAgfSBlbHNlIHtcbiAgICAgIGVuY29kaW5nID0gbGVuZ3RoXG4gICAgICBsZW5ndGggPSB1bmRlZmluZWRcbiAgICB9XG4gIC8vIGxlZ2FjeSB3cml0ZShzdHJpbmcsIGVuY29kaW5nLCBvZmZzZXQsIGxlbmd0aCkgLSByZW1vdmUgaW4gdjAuMTNcbiAgfSBlbHNlIHtcbiAgICB2YXIgc3dhcCA9IGVuY29kaW5nXG4gICAgZW5jb2RpbmcgPSBvZmZzZXRcbiAgICBvZmZzZXQgPSBsZW5ndGggfCAwXG4gICAgbGVuZ3RoID0gc3dhcFxuICB9XG5cbiAgdmFyIHJlbWFpbmluZyA9IHRoaXMubGVuZ3RoIC0gb2Zmc2V0XG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCB8fCBsZW5ndGggPiByZW1haW5pbmcpIGxlbmd0aCA9IHJlbWFpbmluZ1xuXG4gIGlmICgoc3RyaW5nLmxlbmd0aCA+IDAgJiYgKGxlbmd0aCA8IDAgfHwgb2Zmc2V0IDwgMCkpIHx8IG9mZnNldCA+IHRoaXMubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2F0dGVtcHQgdG8gd3JpdGUgb3V0c2lkZSBidWZmZXIgYm91bmRzJylcbiAgfVxuXG4gIGlmICghZW5jb2RpbmcpIGVuY29kaW5nID0gJ3V0ZjgnXG5cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBoZXhXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICAgIHJldHVybiBhc2NpaVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAgIHJldHVybiBiaW5hcnlXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICAvLyBXYXJuaW5nOiBtYXhMZW5ndGggbm90IHRha2VuIGludG8gYWNjb3VudCBpbiBiYXNlNjRXcml0ZVxuICAgICAgICByZXR1cm4gYmFzZTY0V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIHVjczJXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBlbmNvZGluZylcbiAgICAgICAgZW5jb2RpbmcgPSAoJycgKyBlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS50b0pTT04gPSBmdW5jdGlvbiB0b0pTT04gKCkge1xuICByZXR1cm4ge1xuICAgIHR5cGU6ICdCdWZmZXInLFxuICAgIGRhdGE6IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHRoaXMuX2FyciB8fCB0aGlzLCAwKVxuICB9XG59XG5cbmZ1bmN0aW9uIGJhc2U2NFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgaWYgKHN0YXJ0ID09PSAwICYmIGVuZCA9PT0gYnVmLmxlbmd0aCkge1xuICAgIHJldHVybiBiYXNlNjQuZnJvbUJ5dGVBcnJheShidWYpXG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIGJhc2U2NC5mcm9tQnl0ZUFycmF5KGJ1Zi5zbGljZShzdGFydCwgZW5kKSlcbiAgfVxufVxuXG5mdW5jdGlvbiB1dGY4U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG4gIHZhciByZXMgPSBbXVxuXG4gIHZhciBpID0gc3RhcnRcbiAgd2hpbGUgKGkgPCBlbmQpIHtcbiAgICB2YXIgZmlyc3RCeXRlID0gYnVmW2ldXG4gICAgdmFyIGNvZGVQb2ludCA9IG51bGxcbiAgICB2YXIgYnl0ZXNQZXJTZXF1ZW5jZSA9IChmaXJzdEJ5dGUgPiAweEVGKSA/IDRcbiAgICAgIDogKGZpcnN0Qnl0ZSA+IDB4REYpID8gM1xuICAgICAgOiAoZmlyc3RCeXRlID4gMHhCRikgPyAyXG4gICAgICA6IDFcblxuICAgIGlmIChpICsgYnl0ZXNQZXJTZXF1ZW5jZSA8PSBlbmQpIHtcbiAgICAgIHZhciBzZWNvbmRCeXRlLCB0aGlyZEJ5dGUsIGZvdXJ0aEJ5dGUsIHRlbXBDb2RlUG9pbnRcblxuICAgICAgc3dpdGNoIChieXRlc1BlclNlcXVlbmNlKSB7XG4gICAgICAgIGNhc2UgMTpcbiAgICAgICAgICBpZiAoZmlyc3RCeXRlIDwgMHg4MCkge1xuICAgICAgICAgICAgY29kZVBvaW50ID0gZmlyc3RCeXRlXG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgMjpcbiAgICAgICAgICBzZWNvbmRCeXRlID0gYnVmW2kgKyAxXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4MUYpIDw8IDB4NiB8IChzZWNvbmRCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHg3Rikge1xuICAgICAgICAgICAgICBjb2RlUG9pbnQgPSB0ZW1wQ29kZVBvaW50XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgMzpcbiAgICAgICAgICBzZWNvbmRCeXRlID0gYnVmW2kgKyAxXVxuICAgICAgICAgIHRoaXJkQnl0ZSA9IGJ1ZltpICsgMl1cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAodGhpcmRCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHhGKSA8PCAweEMgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpIDw8IDB4NiB8ICh0aGlyZEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweDdGRiAmJiAodGVtcENvZGVQb2ludCA8IDB4RDgwMCB8fCB0ZW1wQ29kZVBvaW50ID4gMHhERkZGKSkge1xuICAgICAgICAgICAgICBjb2RlUG9pbnQgPSB0ZW1wQ29kZVBvaW50XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgNDpcbiAgICAgICAgICBzZWNvbmRCeXRlID0gYnVmW2kgKyAxXVxuICAgICAgICAgIHRoaXJkQnl0ZSA9IGJ1ZltpICsgMl1cbiAgICAgICAgICBmb3VydGhCeXRlID0gYnVmW2kgKyAzXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwICYmICh0aGlyZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAoZm91cnRoQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4RikgPDwgMHgxMiB8IChzZWNvbmRCeXRlICYgMHgzRikgPDwgMHhDIHwgKHRoaXJkQnl0ZSAmIDB4M0YpIDw8IDB4NiB8IChmb3VydGhCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHhGRkZGICYmIHRlbXBDb2RlUG9pbnQgPCAweDExMDAwMCkge1xuICAgICAgICAgICAgICBjb2RlUG9pbnQgPSB0ZW1wQ29kZVBvaW50XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChjb2RlUG9pbnQgPT09IG51bGwpIHtcbiAgICAgIC8vIHdlIGRpZCBub3QgZ2VuZXJhdGUgYSB2YWxpZCBjb2RlUG9pbnQgc28gaW5zZXJ0IGFcbiAgICAgIC8vIHJlcGxhY2VtZW50IGNoYXIgKFUrRkZGRCkgYW5kIGFkdmFuY2Ugb25seSAxIGJ5dGVcbiAgICAgIGNvZGVQb2ludCA9IDB4RkZGRFxuICAgICAgYnl0ZXNQZXJTZXF1ZW5jZSA9IDFcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA+IDB4RkZGRikge1xuICAgICAgLy8gZW5jb2RlIHRvIHV0ZjE2IChzdXJyb2dhdGUgcGFpciBkYW5jZSlcbiAgICAgIGNvZGVQb2ludCAtPSAweDEwMDAwXG4gICAgICByZXMucHVzaChjb2RlUG9pbnQgPj4+IDEwICYgMHgzRkYgfCAweEQ4MDApXG4gICAgICBjb2RlUG9pbnQgPSAweERDMDAgfCBjb2RlUG9pbnQgJiAweDNGRlxuICAgIH1cblxuICAgIHJlcy5wdXNoKGNvZGVQb2ludClcbiAgICBpICs9IGJ5dGVzUGVyU2VxdWVuY2VcbiAgfVxuXG4gIHJldHVybiBkZWNvZGVDb2RlUG9pbnRzQXJyYXkocmVzKVxufVxuXG4vLyBCYXNlZCBvbiBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8yMjc0NzI3Mi82ODA3NDIsIHRoZSBicm93c2VyIHdpdGhcbi8vIHRoZSBsb3dlc3QgbGltaXQgaXMgQ2hyb21lLCB3aXRoIDB4MTAwMDAgYXJncy5cbi8vIFdlIGdvIDEgbWFnbml0dWRlIGxlc3MsIGZvciBzYWZldHlcbnZhciBNQVhfQVJHVU1FTlRTX0xFTkdUSCA9IDB4MTAwMFxuXG5mdW5jdGlvbiBkZWNvZGVDb2RlUG9pbnRzQXJyYXkgKGNvZGVQb2ludHMpIHtcbiAgdmFyIGxlbiA9IGNvZGVQb2ludHMubGVuZ3RoXG4gIGlmIChsZW4gPD0gTUFYX0FSR1VNRU5UU19MRU5HVEgpIHtcbiAgICByZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShTdHJpbmcsIGNvZGVQb2ludHMpIC8vIGF2b2lkIGV4dHJhIHNsaWNlKClcbiAgfVxuXG4gIC8vIERlY29kZSBpbiBjaHVua3MgdG8gYXZvaWQgXCJjYWxsIHN0YWNrIHNpemUgZXhjZWVkZWRcIi5cbiAgdmFyIHJlcyA9ICcnXG4gIHZhciBpID0gMFxuICB3aGlsZSAoaSA8IGxlbikge1xuICAgIHJlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFxuICAgICAgU3RyaW5nLFxuICAgICAgY29kZVBvaW50cy5zbGljZShpLCBpICs9IE1BWF9BUkdVTUVOVFNfTEVOR1RIKVxuICAgIClcbiAgfVxuICByZXR1cm4gcmVzXG59XG5cbmZ1bmN0aW9uIGFzY2lpU2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgcmV0ID0gJydcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgcmV0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnVmW2ldICYgMHg3RilcbiAgfVxuICByZXR1cm4gcmV0XG59XG5cbmZ1bmN0aW9uIGJpbmFyeVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIHJldCA9ICcnXG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcblxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIHJldCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ1ZltpXSlcbiAgfVxuICByZXR1cm4gcmV0XG59XG5cbmZ1bmN0aW9uIGhleFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxlbiA9IGJ1Zi5sZW5ndGhcblxuICBpZiAoIXN0YXJ0IHx8IHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIGlmICghZW5kIHx8IGVuZCA8IDAgfHwgZW5kID4gbGVuKSBlbmQgPSBsZW5cblxuICB2YXIgb3V0ID0gJydcbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICBvdXQgKz0gdG9IZXgoYnVmW2ldKVxuICB9XG4gIHJldHVybiBvdXRcbn1cblxuZnVuY3Rpb24gdXRmMTZsZVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGJ5dGVzID0gYnVmLnNsaWNlKHN0YXJ0LCBlbmQpXG4gIHZhciByZXMgPSAnJ1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSArPSAyKSB7XG4gICAgcmVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnl0ZXNbaV0gKyBieXRlc1tpICsgMV0gKiAyNTYpXG4gIH1cbiAgcmV0dXJuIHJlc1xufVxuXG5CdWZmZXIucHJvdG90eXBlLnNsaWNlID0gZnVuY3Rpb24gc2xpY2UgKHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxlbiA9IHRoaXMubGVuZ3RoXG4gIHN0YXJ0ID0gfn5zdGFydFxuICBlbmQgPSBlbmQgPT09IHVuZGVmaW5lZCA/IGxlbiA6IH5+ZW5kXG5cbiAgaWYgKHN0YXJ0IDwgMCkge1xuICAgIHN0YXJ0ICs9IGxlblxuICAgIGlmIChzdGFydCA8IDApIHN0YXJ0ID0gMFxuICB9IGVsc2UgaWYgKHN0YXJ0ID4gbGVuKSB7XG4gICAgc3RhcnQgPSBsZW5cbiAgfVxuXG4gIGlmIChlbmQgPCAwKSB7XG4gICAgZW5kICs9IGxlblxuICAgIGlmIChlbmQgPCAwKSBlbmQgPSAwXG4gIH0gZWxzZSBpZiAoZW5kID4gbGVuKSB7XG4gICAgZW5kID0gbGVuXG4gIH1cblxuICBpZiAoZW5kIDwgc3RhcnQpIGVuZCA9IHN0YXJ0XG5cbiAgdmFyIG5ld0J1ZlxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICBuZXdCdWYgPSBCdWZmZXIuX2F1Z21lbnQodGhpcy5zdWJhcnJheShzdGFydCwgZW5kKSlcbiAgfSBlbHNlIHtcbiAgICB2YXIgc2xpY2VMZW4gPSBlbmQgLSBzdGFydFxuICAgIG5ld0J1ZiA9IG5ldyBCdWZmZXIoc2xpY2VMZW4sIHVuZGVmaW5lZClcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNsaWNlTGVuOyBpKyspIHtcbiAgICAgIG5ld0J1ZltpXSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfVxuXG4gIGlmIChuZXdCdWYubGVuZ3RoKSBuZXdCdWYucGFyZW50ID0gdGhpcy5wYXJlbnQgfHwgdGhpc1xuXG4gIHJldHVybiBuZXdCdWZcbn1cblxuLypcbiAqIE5lZWQgdG8gbWFrZSBzdXJlIHRoYXQgYnVmZmVyIGlzbid0IHRyeWluZyB0byB3cml0ZSBvdXQgb2YgYm91bmRzLlxuICovXG5mdW5jdGlvbiBjaGVja09mZnNldCAob2Zmc2V0LCBleHQsIGxlbmd0aCkge1xuICBpZiAoKG9mZnNldCAlIDEpICE9PSAwIHx8IG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdvZmZzZXQgaXMgbm90IHVpbnQnKVxuICBpZiAob2Zmc2V0ICsgZXh0ID4gbGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignVHJ5aW5nIHRvIGFjY2VzcyBiZXlvbmQgYnVmZmVyIGxlbmd0aCcpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnRMRSA9IGZ1bmN0aW9uIHJlYWRVSW50TEUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIGldICogbXVsXG4gIH1cblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnRCRSA9IGZ1bmN0aW9uIHJlYWRVSW50QkUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG4gIH1cblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAtLWJ5dGVMZW5ndGhdXG4gIHZhciBtdWwgPSAxXG4gIHdoaWxlIChieXRlTGVuZ3RoID4gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIC0tYnl0ZUxlbmd0aF0gKiBtdWxcbiAgfVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDggPSBmdW5jdGlvbiByZWFkVUludDggKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAxLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIHRoaXNbb2Zmc2V0XVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MTZMRSA9IGZ1bmN0aW9uIHJlYWRVSW50MTZMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gdGhpc1tvZmZzZXRdIHwgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDE2QkUgPSBmdW5jdGlvbiByZWFkVUludDE2QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuICh0aGlzW29mZnNldF0gPDwgOCkgfCB0aGlzW29mZnNldCArIDFdXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQzMkxFID0gZnVuY3Rpb24gcmVhZFVJbnQzMkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICgodGhpc1tvZmZzZXRdKSB8XG4gICAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KSB8XG4gICAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCAxNikpICtcbiAgICAgICh0aGlzW29mZnNldCArIDNdICogMHgxMDAwMDAwKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MzJCRSA9IGZ1bmN0aW9uIHJlYWRVSW50MzJCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAodGhpc1tvZmZzZXRdICogMHgxMDAwMDAwKSArXG4gICAgKCh0aGlzW29mZnNldCArIDFdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgOCkgfFxuICAgIHRoaXNbb2Zmc2V0ICsgM10pXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludExFID0gZnVuY3Rpb24gcmVhZEludExFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XVxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyBpXSAqIG11bFxuICB9XG4gIG11bCAqPSAweDgwXG5cbiAgaWYgKHZhbCA+PSBtdWwpIHZhbCAtPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aClcblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludEJFID0gZnVuY3Rpb24gcmVhZEludEJFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIGkgPSBieXRlTGVuZ3RoXG4gIHZhciBtdWwgPSAxXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIC0taV1cbiAgd2hpbGUgKGkgPiAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgLS1pXSAqIG11bFxuICB9XG4gIG11bCAqPSAweDgwXG5cbiAgaWYgKHZhbCA+PSBtdWwpIHZhbCAtPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aClcblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDggPSBmdW5jdGlvbiByZWFkSW50OCAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDEsIHRoaXMubGVuZ3RoKVxuICBpZiAoISh0aGlzW29mZnNldF0gJiAweDgwKSkgcmV0dXJuICh0aGlzW29mZnNldF0pXG4gIHJldHVybiAoKDB4ZmYgLSB0aGlzW29mZnNldF0gKyAxKSAqIC0xKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQxNkxFID0gZnVuY3Rpb24gcmVhZEludDE2TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XSB8ICh0aGlzW29mZnNldCArIDFdIDw8IDgpXG4gIHJldHVybiAodmFsICYgMHg4MDAwKSA/IHZhbCB8IDB4RkZGRjAwMDAgOiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MTZCRSA9IGZ1bmN0aW9uIHJlYWRJbnQxNkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIDFdIHwgKHRoaXNbb2Zmc2V0XSA8PCA4KVxuICByZXR1cm4gKHZhbCAmIDB4ODAwMCkgPyB2YWwgfCAweEZGRkYwMDAwIDogdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDMyTEUgPSBmdW5jdGlvbiByZWFkSW50MzJMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAodGhpc1tvZmZzZXRdKSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOCkgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgM10gPDwgMjQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDMyQkUgPSBmdW5jdGlvbiByZWFkSW50MzJCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAodGhpc1tvZmZzZXRdIDw8IDI0KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCA4KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgM10pXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEZsb2F0TEUgPSBmdW5jdGlvbiByZWFkRmxvYXRMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgdHJ1ZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEZsb2F0QkUgPSBmdW5jdGlvbiByZWFkRmxvYXRCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgZmFsc2UsIDIzLCA0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWREb3VibGVMRSA9IGZ1bmN0aW9uIHJlYWREb3VibGVMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDgsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgdHJ1ZSwgNTIsIDgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUJFID0gZnVuY3Rpb24gcmVhZERvdWJsZUJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgOCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCBmYWxzZSwgNTIsIDgpXG59XG5cbmZ1bmN0aW9uIGNoZWNrSW50IChidWYsIHZhbHVlLCBvZmZzZXQsIGV4dCwgbWF4LCBtaW4pIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoYnVmKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignYnVmZmVyIG11c3QgYmUgYSBCdWZmZXIgaW5zdGFuY2UnKVxuICBpZiAodmFsdWUgPiBtYXggfHwgdmFsdWUgPCBtaW4pIHRocm93IG5ldyBSYW5nZUVycm9yKCd2YWx1ZSBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludExFID0gZnVuY3Rpb24gd3JpdGVVSW50TEUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKSwgMClcblxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludEJFID0gZnVuY3Rpb24gd3JpdGVVSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKSwgMClcblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDggPSBmdW5jdGlvbiB3cml0ZVVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4ZmYsIDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MTYgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgMik7IGkgPCBqOyBpKyspIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgJiAoMHhmZiA8PCAoOCAqIChsaXR0bGVFbmRpYW4gPyBpIDogMSAtIGkpKSkpID4+PlxuICAgICAgKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkgKiA4XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlVUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHhmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MzIgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBmb3IgKHZhciBpID0gMCwgaiA9IE1hdGgubWluKGJ1Zi5sZW5ndGggLSBvZmZzZXQsIDQpOyBpIDwgajsgaSsrKSB7XG4gICAgYnVmW29mZnNldCArIGldID0gKHZhbHVlID4+PiAobGl0dGxlRW5kaWFuID8gaSA6IDMgLSBpKSAqIDgpICYgMHhmZlxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlVUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHhmZmZmZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludExFID0gZnVuY3Rpb24gd3JpdGVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IDBcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHN1YiA9IHZhbHVlIDwgMCA/IDEgOiAwXG4gIHRoaXNbb2Zmc2V0XSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAoKHZhbHVlIC8gbXVsKSA+PiAwKSAtIHN1YiAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnRCRSA9IGZ1bmN0aW9uIHdyaXRlSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIHZhciBsaW1pdCA9IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoIC0gMSlcblxuICAgIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIGxpbWl0IC0gMSwgLWxpbWl0KVxuICB9XG5cbiAgdmFyIGkgPSBieXRlTGVuZ3RoIC0gMVxuICB2YXIgbXVsID0gMVxuICB2YXIgc3ViID0gdmFsdWUgPCAwID8gMSA6IDBcbiAgdGhpc1tvZmZzZXQgKyBpXSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoLS1pID49IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKCh2YWx1ZSAvIG11bCkgPj4gMCkgLSBzdWIgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50OCA9IGZ1bmN0aW9uIHdyaXRlSW50OCAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAxLCAweDdmLCAtMHg4MClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkgdmFsdWUgPSBNYXRoLmZsb29yKHZhbHVlKVxuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmYgKyB2YWx1ZSArIDFcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDE2TEUgPSBmdW5jdGlvbiB3cml0ZUludDE2TEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHg3ZmZmLCAtMHg4MDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlSW50MTZCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweDdmZmYsIC0weDgwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlSW50MzJMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweDdmZmZmZmZmLCAtMHg4MDAwMDAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgPj4+IDI0KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDMyQkUgPSBmdW5jdGlvbiB3cml0ZUludDMyQkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHg3ZmZmZmZmZiwgLTB4ODAwMDAwMDApXG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuZnVuY3Rpb24gY2hlY2tJRUVFNzU0IChidWYsIHZhbHVlLCBvZmZzZXQsIGV4dCwgbWF4LCBtaW4pIHtcbiAgaWYgKHZhbHVlID4gbWF4IHx8IHZhbHVlIDwgbWluKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcigndmFsdWUgaXMgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBidWYubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignaW5kZXggb3V0IG9mIHJhbmdlJylcbiAgaWYgKG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5mdW5jdGlvbiB3cml0ZUZsb2F0IChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDQsIDMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgsIC0zLjQwMjgyMzQ2NjM4NTI4ODZlKzM4KVxuICB9XG4gIGllZWU3NTQud3JpdGUoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4sIDIzLCA0KVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRmxvYXRMRSA9IGZ1bmN0aW9uIHdyaXRlRmxvYXRMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRmxvYXQodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSwgbm9Bc3NlcnQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdEJFID0gZnVuY3Rpb24gd3JpdGVGbG9hdEJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSwgbm9Bc3NlcnQpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRG91YmxlIChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDgsIDEuNzk3NjkzMTM0ODYyMzE1N0UrMzA4LCAtMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgNTIsIDgpXG4gIHJldHVybiBvZmZzZXQgKyA4XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVEb3VibGVMRSA9IGZ1bmN0aW9uIHdyaXRlRG91YmxlTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZURvdWJsZSh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUJFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuLy8gY29weSh0YXJnZXRCdWZmZXIsIHRhcmdldFN0YXJ0PTAsIHNvdXJjZVN0YXJ0PTAsIHNvdXJjZUVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5jb3B5ID0gZnVuY3Rpb24gY29weSAodGFyZ2V0LCB0YXJnZXRTdGFydCwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXN0YXJ0KSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgJiYgZW5kICE9PSAwKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0U3RhcnQgPj0gdGFyZ2V0Lmxlbmd0aCkgdGFyZ2V0U3RhcnQgPSB0YXJnZXQubGVuZ3RoXG4gIGlmICghdGFyZ2V0U3RhcnQpIHRhcmdldFN0YXJ0ID0gMFxuICBpZiAoZW5kID4gMCAmJiBlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICAvLyBDb3B5IDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVybiAwXG4gIGlmICh0YXJnZXQubGVuZ3RoID09PSAwIHx8IHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gMFxuXG4gIC8vIEZhdGFsIGVycm9yIGNvbmRpdGlvbnNcbiAgaWYgKHRhcmdldFN0YXJ0IDwgMCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCd0YXJnZXRTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgfVxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlU3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlRW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIC8vIEFyZSB3ZSBvb2I/XG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKHRhcmdldC5sZW5ndGggLSB0YXJnZXRTdGFydCA8IGVuZCAtIHN0YXJ0KSB7XG4gICAgZW5kID0gdGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0ICsgc3RhcnRcbiAgfVxuXG4gIHZhciBsZW4gPSBlbmQgLSBzdGFydFxuICB2YXIgaVxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQgJiYgc3RhcnQgPCB0YXJnZXRTdGFydCAmJiB0YXJnZXRTdGFydCA8IGVuZCkge1xuICAgIC8vIGRlc2NlbmRpbmcgY29weSBmcm9tIGVuZFxuICAgIGZvciAoaSA9IGxlbiAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICB0YXJnZXRbaSArIHRhcmdldFN0YXJ0XSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfSBlbHNlIGlmIChsZW4gPCAxMDAwIHx8ICFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIGFzY2VuZGluZyBjb3B5IGZyb20gc3RhcnRcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHRhcmdldC5fc2V0KHRoaXMuc3ViYXJyYXkoc3RhcnQsIHN0YXJ0ICsgbGVuKSwgdGFyZ2V0U3RhcnQpXG4gIH1cblxuICByZXR1cm4gbGVuXG59XG5cbi8vIGZpbGwodmFsdWUsIHN0YXJ0PTAsIGVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5maWxsID0gZnVuY3Rpb24gZmlsbCAodmFsdWUsIHN0YXJ0LCBlbmQpIHtcbiAgaWYgKCF2YWx1ZSkgdmFsdWUgPSAwXG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCkgZW5kID0gdGhpcy5sZW5ndGhcblxuICBpZiAoZW5kIDwgc3RhcnQpIHRocm93IG5ldyBSYW5nZUVycm9yKCdlbmQgPCBzdGFydCcpXG5cbiAgLy8gRmlsbCAwIGJ5dGVzOyB3ZSdyZSBkb25lXG4gIGlmIChlbmQgPT09IHN0YXJ0KSByZXR1cm5cbiAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm5cblxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwIHx8IGVuZCA+IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignZW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIHZhciBpXG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdGhpc1tpXSA9IHZhbHVlXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHZhciBieXRlcyA9IHV0ZjhUb0J5dGVzKHZhbHVlLnRvU3RyaW5nKCkpXG4gICAgdmFyIGxlbiA9IGJ5dGVzLmxlbmd0aFxuICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICAgIHRoaXNbaV0gPSBieXRlc1tpICUgbGVuXVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzXG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBgQXJyYXlCdWZmZXJgIHdpdGggdGhlICpjb3BpZWQqIG1lbW9yeSBvZiB0aGUgYnVmZmVyIGluc3RhbmNlLlxuICogQWRkZWQgaW4gTm9kZSAwLjEyLiBPbmx5IGF2YWlsYWJsZSBpbiBicm93c2VycyB0aGF0IHN1cHBvcnQgQXJyYXlCdWZmZXIuXG4gKi9cbkJ1ZmZlci5wcm90b3R5cGUudG9BcnJheUJ1ZmZlciA9IGZ1bmN0aW9uIHRvQXJyYXlCdWZmZXIgKCkge1xuICBpZiAodHlwZW9mIFVpbnQ4QXJyYXkgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgICByZXR1cm4gKG5ldyBCdWZmZXIodGhpcykpLmJ1ZmZlclxuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgYnVmID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5sZW5ndGgpXG4gICAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gYnVmLmxlbmd0aDsgaSA8IGxlbjsgaSArPSAxKSB7XG4gICAgICAgIGJ1ZltpXSA9IHRoaXNbaV1cbiAgICAgIH1cbiAgICAgIHJldHVybiBidWYuYnVmZmVyXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0J1ZmZlci50b0FycmF5QnVmZmVyIG5vdCBzdXBwb3J0ZWQgaW4gdGhpcyBicm93c2VyJylcbiAgfVxufVxuXG4vLyBIRUxQRVIgRlVOQ1RJT05TXG4vLyA9PT09PT09PT09PT09PT09XG5cbnZhciBCUCA9IEJ1ZmZlci5wcm90b3R5cGVcblxuLyoqXG4gKiBBdWdtZW50IGEgVWludDhBcnJheSAqaW5zdGFuY2UqIChub3QgdGhlIFVpbnQ4QXJyYXkgY2xhc3MhKSB3aXRoIEJ1ZmZlciBtZXRob2RzXG4gKi9cbkJ1ZmZlci5fYXVnbWVudCA9IGZ1bmN0aW9uIF9hdWdtZW50IChhcnIpIHtcbiAgYXJyLmNvbnN0cnVjdG9yID0gQnVmZmVyXG4gIGFyci5faXNCdWZmZXIgPSB0cnVlXG5cbiAgLy8gc2F2ZSByZWZlcmVuY2UgdG8gb3JpZ2luYWwgVWludDhBcnJheSBzZXQgbWV0aG9kIGJlZm9yZSBvdmVyd3JpdGluZ1xuICBhcnIuX3NldCA9IGFyci5zZXRcblxuICAvLyBkZXByZWNhdGVkXG4gIGFyci5nZXQgPSBCUC5nZXRcbiAgYXJyLnNldCA9IEJQLnNldFxuXG4gIGFyci53cml0ZSA9IEJQLndyaXRlXG4gIGFyci50b1N0cmluZyA9IEJQLnRvU3RyaW5nXG4gIGFyci50b0xvY2FsZVN0cmluZyA9IEJQLnRvU3RyaW5nXG4gIGFyci50b0pTT04gPSBCUC50b0pTT05cbiAgYXJyLmVxdWFscyA9IEJQLmVxdWFsc1xuICBhcnIuY29tcGFyZSA9IEJQLmNvbXBhcmVcbiAgYXJyLmluZGV4T2YgPSBCUC5pbmRleE9mXG4gIGFyci5jb3B5ID0gQlAuY29weVxuICBhcnIuc2xpY2UgPSBCUC5zbGljZVxuICBhcnIucmVhZFVJbnRMRSA9IEJQLnJlYWRVSW50TEVcbiAgYXJyLnJlYWRVSW50QkUgPSBCUC5yZWFkVUludEJFXG4gIGFyci5yZWFkVUludDggPSBCUC5yZWFkVUludDhcbiAgYXJyLnJlYWRVSW50MTZMRSA9IEJQLnJlYWRVSW50MTZMRVxuICBhcnIucmVhZFVJbnQxNkJFID0gQlAucmVhZFVJbnQxNkJFXG4gIGFyci5yZWFkVUludDMyTEUgPSBCUC5yZWFkVUludDMyTEVcbiAgYXJyLnJlYWRVSW50MzJCRSA9IEJQLnJlYWRVSW50MzJCRVxuICBhcnIucmVhZEludExFID0gQlAucmVhZEludExFXG4gIGFyci5yZWFkSW50QkUgPSBCUC5yZWFkSW50QkVcbiAgYXJyLnJlYWRJbnQ4ID0gQlAucmVhZEludDhcbiAgYXJyLnJlYWRJbnQxNkxFID0gQlAucmVhZEludDE2TEVcbiAgYXJyLnJlYWRJbnQxNkJFID0gQlAucmVhZEludDE2QkVcbiAgYXJyLnJlYWRJbnQzMkxFID0gQlAucmVhZEludDMyTEVcbiAgYXJyLnJlYWRJbnQzMkJFID0gQlAucmVhZEludDMyQkVcbiAgYXJyLnJlYWRGbG9hdExFID0gQlAucmVhZEZsb2F0TEVcbiAgYXJyLnJlYWRGbG9hdEJFID0gQlAucmVhZEZsb2F0QkVcbiAgYXJyLnJlYWREb3VibGVMRSA9IEJQLnJlYWREb3VibGVMRVxuICBhcnIucmVhZERvdWJsZUJFID0gQlAucmVhZERvdWJsZUJFXG4gIGFyci53cml0ZVVJbnQ4ID0gQlAud3JpdGVVSW50OFxuICBhcnIud3JpdGVVSW50TEUgPSBCUC53cml0ZVVJbnRMRVxuICBhcnIud3JpdGVVSW50QkUgPSBCUC53cml0ZVVJbnRCRVxuICBhcnIud3JpdGVVSW50MTZMRSA9IEJQLndyaXRlVUludDE2TEVcbiAgYXJyLndyaXRlVUludDE2QkUgPSBCUC53cml0ZVVJbnQxNkJFXG4gIGFyci53cml0ZVVJbnQzMkxFID0gQlAud3JpdGVVSW50MzJMRVxuICBhcnIud3JpdGVVSW50MzJCRSA9IEJQLndyaXRlVUludDMyQkVcbiAgYXJyLndyaXRlSW50TEUgPSBCUC53cml0ZUludExFXG4gIGFyci53cml0ZUludEJFID0gQlAud3JpdGVJbnRCRVxuICBhcnIud3JpdGVJbnQ4ID0gQlAud3JpdGVJbnQ4XG4gIGFyci53cml0ZUludDE2TEUgPSBCUC53cml0ZUludDE2TEVcbiAgYXJyLndyaXRlSW50MTZCRSA9IEJQLndyaXRlSW50MTZCRVxuICBhcnIud3JpdGVJbnQzMkxFID0gQlAud3JpdGVJbnQzMkxFXG4gIGFyci53cml0ZUludDMyQkUgPSBCUC53cml0ZUludDMyQkVcbiAgYXJyLndyaXRlRmxvYXRMRSA9IEJQLndyaXRlRmxvYXRMRVxuICBhcnIud3JpdGVGbG9hdEJFID0gQlAud3JpdGVGbG9hdEJFXG4gIGFyci53cml0ZURvdWJsZUxFID0gQlAud3JpdGVEb3VibGVMRVxuICBhcnIud3JpdGVEb3VibGVCRSA9IEJQLndyaXRlRG91YmxlQkVcbiAgYXJyLmZpbGwgPSBCUC5maWxsXG4gIGFyci5pbnNwZWN0ID0gQlAuaW5zcGVjdFxuICBhcnIudG9BcnJheUJ1ZmZlciA9IEJQLnRvQXJyYXlCdWZmZXJcblxuICByZXR1cm4gYXJyXG59XG5cbnZhciBJTlZBTElEX0JBU0U2NF9SRSA9IC9bXitcXC8wLTlBLVphLXotX10vZ1xuXG5mdW5jdGlvbiBiYXNlNjRjbGVhbiAoc3RyKSB7XG4gIC8vIE5vZGUgc3RyaXBzIG91dCBpbnZhbGlkIGNoYXJhY3RlcnMgbGlrZSBcXG4gYW5kIFxcdCBmcm9tIHRoZSBzdHJpbmcsIGJhc2U2NC1qcyBkb2VzIG5vdFxuICBzdHIgPSBzdHJpbmd0cmltKHN0cikucmVwbGFjZShJTlZBTElEX0JBU0U2NF9SRSwgJycpXG4gIC8vIE5vZGUgY29udmVydHMgc3RyaW5ncyB3aXRoIGxlbmd0aCA8IDIgdG8gJydcbiAgaWYgKHN0ci5sZW5ndGggPCAyKSByZXR1cm4gJydcbiAgLy8gTm9kZSBhbGxvd3MgZm9yIG5vbi1wYWRkZWQgYmFzZTY0IHN0cmluZ3MgKG1pc3NpbmcgdHJhaWxpbmcgPT09KSwgYmFzZTY0LWpzIGRvZXMgbm90XG4gIHdoaWxlIChzdHIubGVuZ3RoICUgNCAhPT0gMCkge1xuICAgIHN0ciA9IHN0ciArICc9J1xuICB9XG4gIHJldHVybiBzdHJcbn1cblxuZnVuY3Rpb24gc3RyaW5ndHJpbSAoc3RyKSB7XG4gIGlmIChzdHIudHJpbSkgcmV0dXJuIHN0ci50cmltKClcbiAgcmV0dXJuIHN0ci5yZXBsYWNlKC9eXFxzK3xcXHMrJC9nLCAnJylcbn1cblxuZnVuY3Rpb24gdG9IZXggKG4pIHtcbiAgaWYgKG4gPCAxNikgcmV0dXJuICcwJyArIG4udG9TdHJpbmcoMTYpXG4gIHJldHVybiBuLnRvU3RyaW5nKDE2KVxufVxuXG5mdW5jdGlvbiB1dGY4VG9CeXRlcyAoc3RyaW5nLCB1bml0cykge1xuICB1bml0cyA9IHVuaXRzIHx8IEluZmluaXR5XG4gIHZhciBjb2RlUG9pbnRcbiAgdmFyIGxlbmd0aCA9IHN0cmluZy5sZW5ndGhcbiAgdmFyIGxlYWRTdXJyb2dhdGUgPSBudWxsXG4gIHZhciBieXRlcyA9IFtdXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIGNvZGVQb2ludCA9IHN0cmluZy5jaGFyQ29kZUF0KGkpXG5cbiAgICAvLyBpcyBzdXJyb2dhdGUgY29tcG9uZW50XG4gICAgaWYgKGNvZGVQb2ludCA+IDB4RDdGRiAmJiBjb2RlUG9pbnQgPCAweEUwMDApIHtcbiAgICAgIC8vIGxhc3QgY2hhciB3YXMgYSBsZWFkXG4gICAgICBpZiAoIWxlYWRTdXJyb2dhdGUpIHtcbiAgICAgICAgLy8gbm8gbGVhZCB5ZXRcbiAgICAgICAgaWYgKGNvZGVQb2ludCA+IDB4REJGRikge1xuICAgICAgICAgIC8vIHVuZXhwZWN0ZWQgdHJhaWxcbiAgICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9IGVsc2UgaWYgKGkgKyAxID09PSBsZW5ndGgpIHtcbiAgICAgICAgICAvLyB1bnBhaXJlZCBsZWFkXG4gICAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHZhbGlkIGxlYWRcbiAgICAgICAgbGVhZFN1cnJvZ2F0ZSA9IGNvZGVQb2ludFxuXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIC8vIDIgbGVhZHMgaW4gYSByb3dcbiAgICAgIGlmIChjb2RlUG9pbnQgPCAweERDMDApIHtcbiAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgIGxlYWRTdXJyb2dhdGUgPSBjb2RlUG9pbnRcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gdmFsaWQgc3Vycm9nYXRlIHBhaXJcbiAgICAgIGNvZGVQb2ludCA9IChsZWFkU3Vycm9nYXRlIC0gMHhEODAwIDw8IDEwIHwgY29kZVBvaW50IC0gMHhEQzAwKSArIDB4MTAwMDBcbiAgICB9IGVsc2UgaWYgKGxlYWRTdXJyb2dhdGUpIHtcbiAgICAgIC8vIHZhbGlkIGJtcCBjaGFyLCBidXQgbGFzdCBjaGFyIHdhcyBhIGxlYWRcbiAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgIH1cblxuICAgIGxlYWRTdXJyb2dhdGUgPSBudWxsXG5cbiAgICAvLyBlbmNvZGUgdXRmOFxuICAgIGlmIChjb2RlUG9pbnQgPCAweDgwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDEpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goY29kZVBvaW50KVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHg4MDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMikgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiB8IDB4QzAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDEwMDAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDMpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweEMgfCAweEUwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2ICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDExMDAwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSA0KSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHgxMiB8IDB4RjAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweEMgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY29kZSBwb2ludCcpXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGJ5dGVzXG59XG5cbmZ1bmN0aW9uIGFzY2lpVG9CeXRlcyAoc3RyKSB7XG4gIHZhciBieXRlQXJyYXkgPSBbXVxuICBmb3IgKHZhciBpID0gMDsgaSA8IHN0ci5sZW5ndGg7IGkrKykge1xuICAgIC8vIE5vZGUncyBjb2RlIHNlZW1zIHRvIGJlIGRvaW5nIHRoaXMgYW5kIG5vdCAmIDB4N0YuLlxuICAgIGJ5dGVBcnJheS5wdXNoKHN0ci5jaGFyQ29kZUF0KGkpICYgMHhGRilcbiAgfVxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIHV0ZjE2bGVUb0J5dGVzIChzdHIsIHVuaXRzKSB7XG4gIHZhciBjLCBoaSwgbG9cbiAgdmFyIGJ5dGVBcnJheSA9IFtdXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKCh1bml0cyAtPSAyKSA8IDApIGJyZWFrXG5cbiAgICBjID0gc3RyLmNoYXJDb2RlQXQoaSlcbiAgICBoaSA9IGMgPj4gOFxuICAgIGxvID0gYyAlIDI1NlxuICAgIGJ5dGVBcnJheS5wdXNoKGxvKVxuICAgIGJ5dGVBcnJheS5wdXNoKGhpKVxuICB9XG5cbiAgcmV0dXJuIGJ5dGVBcnJheVxufVxuXG5mdW5jdGlvbiBiYXNlNjRUb0J5dGVzIChzdHIpIHtcbiAgcmV0dXJuIGJhc2U2NC50b0J5dGVBcnJheShiYXNlNjRjbGVhbihzdHIpKVxufVxuXG5mdW5jdGlvbiBibGl0QnVmZmVyIChzcmMsIGRzdCwgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIGlmICgoaSArIG9mZnNldCA+PSBkc3QubGVuZ3RoKSB8fCAoaSA+PSBzcmMubGVuZ3RoKSkgYnJlYWtcbiAgICBkc3RbaSArIG9mZnNldF0gPSBzcmNbaV1cbiAgfVxuICByZXR1cm4gaVxufVxuIiwidmFyIGxvb2t1cCA9ICdBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvJztcblxuOyhmdW5jdGlvbiAoZXhwb3J0cykge1xuXHQndXNlIHN0cmljdCc7XG5cbiAgdmFyIEFyciA9ICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpXG4gICAgPyBVaW50OEFycmF5XG4gICAgOiBBcnJheVxuXG5cdHZhciBQTFVTICAgPSAnKycuY2hhckNvZGVBdCgwKVxuXHR2YXIgU0xBU0ggID0gJy8nLmNoYXJDb2RlQXQoMClcblx0dmFyIE5VTUJFUiA9ICcwJy5jaGFyQ29kZUF0KDApXG5cdHZhciBMT1dFUiAgPSAnYScuY2hhckNvZGVBdCgwKVxuXHR2YXIgVVBQRVIgID0gJ0EnLmNoYXJDb2RlQXQoMClcblx0dmFyIFBMVVNfVVJMX1NBRkUgPSAnLScuY2hhckNvZGVBdCgwKVxuXHR2YXIgU0xBU0hfVVJMX1NBRkUgPSAnXycuY2hhckNvZGVBdCgwKVxuXG5cdGZ1bmN0aW9uIGRlY29kZSAoZWx0KSB7XG5cdFx0dmFyIGNvZGUgPSBlbHQuY2hhckNvZGVBdCgwKVxuXHRcdGlmIChjb2RlID09PSBQTFVTIHx8XG5cdFx0ICAgIGNvZGUgPT09IFBMVVNfVVJMX1NBRkUpXG5cdFx0XHRyZXR1cm4gNjIgLy8gJysnXG5cdFx0aWYgKGNvZGUgPT09IFNMQVNIIHx8XG5cdFx0ICAgIGNvZGUgPT09IFNMQVNIX1VSTF9TQUZFKVxuXHRcdFx0cmV0dXJuIDYzIC8vICcvJ1xuXHRcdGlmIChjb2RlIDwgTlVNQkVSKVxuXHRcdFx0cmV0dXJuIC0xIC8vbm8gbWF0Y2hcblx0XHRpZiAoY29kZSA8IE5VTUJFUiArIDEwKVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBOVU1CRVIgKyAyNiArIDI2XG5cdFx0aWYgKGNvZGUgPCBVUFBFUiArIDI2KVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBVUFBFUlxuXHRcdGlmIChjb2RlIDwgTE9XRVIgKyAyNilcblx0XHRcdHJldHVybiBjb2RlIC0gTE9XRVIgKyAyNlxuXHR9XG5cblx0ZnVuY3Rpb24gYjY0VG9CeXRlQXJyYXkgKGI2NCkge1xuXHRcdHZhciBpLCBqLCBsLCB0bXAsIHBsYWNlSG9sZGVycywgYXJyXG5cblx0XHRpZiAoYjY0Lmxlbmd0aCAlIDQgPiAwKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgc3RyaW5nLiBMZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIDQnKVxuXHRcdH1cblxuXHRcdC8vIHRoZSBudW1iZXIgb2YgZXF1YWwgc2lnbnMgKHBsYWNlIGhvbGRlcnMpXG5cdFx0Ly8gaWYgdGhlcmUgYXJlIHR3byBwbGFjZWhvbGRlcnMsIHRoYW4gdGhlIHR3byBjaGFyYWN0ZXJzIGJlZm9yZSBpdFxuXHRcdC8vIHJlcHJlc2VudCBvbmUgYnl0ZVxuXHRcdC8vIGlmIHRoZXJlIGlzIG9ubHkgb25lLCB0aGVuIHRoZSB0aHJlZSBjaGFyYWN0ZXJzIGJlZm9yZSBpdCByZXByZXNlbnQgMiBieXRlc1xuXHRcdC8vIHRoaXMgaXMganVzdCBhIGNoZWFwIGhhY2sgdG8gbm90IGRvIGluZGV4T2YgdHdpY2Vcblx0XHR2YXIgbGVuID0gYjY0Lmxlbmd0aFxuXHRcdHBsYWNlSG9sZGVycyA9ICc9JyA9PT0gYjY0LmNoYXJBdChsZW4gLSAyKSA/IDIgOiAnPScgPT09IGI2NC5jaGFyQXQobGVuIC0gMSkgPyAxIDogMFxuXG5cdFx0Ly8gYmFzZTY0IGlzIDQvMyArIHVwIHRvIHR3byBjaGFyYWN0ZXJzIG9mIHRoZSBvcmlnaW5hbCBkYXRhXG5cdFx0YXJyID0gbmV3IEFycihiNjQubGVuZ3RoICogMyAvIDQgLSBwbGFjZUhvbGRlcnMpXG5cblx0XHQvLyBpZiB0aGVyZSBhcmUgcGxhY2Vob2xkZXJzLCBvbmx5IGdldCB1cCB0byB0aGUgbGFzdCBjb21wbGV0ZSA0IGNoYXJzXG5cdFx0bCA9IHBsYWNlSG9sZGVycyA+IDAgPyBiNjQubGVuZ3RoIC0gNCA6IGI2NC5sZW5ndGhcblxuXHRcdHZhciBMID0gMFxuXG5cdFx0ZnVuY3Rpb24gcHVzaCAodikge1xuXHRcdFx0YXJyW0wrK10gPSB2XG5cdFx0fVxuXG5cdFx0Zm9yIChpID0gMCwgaiA9IDA7IGkgPCBsOyBpICs9IDQsIGogKz0gMykge1xuXHRcdFx0dG1wID0gKGRlY29kZShiNjQuY2hhckF0KGkpKSA8PCAxOCkgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA8PCAxMikgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDIpKSA8PCA2KSB8IGRlY29kZShiNjQuY2hhckF0KGkgKyAzKSlcblx0XHRcdHB1c2goKHRtcCAmIDB4RkYwMDAwKSA+PiAxNilcblx0XHRcdHB1c2goKHRtcCAmIDB4RkYwMCkgPj4gOClcblx0XHRcdHB1c2godG1wICYgMHhGRilcblx0XHR9XG5cblx0XHRpZiAocGxhY2VIb2xkZXJzID09PSAyKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDIpIHwgKGRlY29kZShiNjQuY2hhckF0KGkgKyAxKSkgPj4gNClcblx0XHRcdHB1c2godG1wICYgMHhGRilcblx0XHR9IGVsc2UgaWYgKHBsYWNlSG9sZGVycyA9PT0gMSkge1xuXHRcdFx0dG1wID0gKGRlY29kZShiNjQuY2hhckF0KGkpKSA8PCAxMCkgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA8PCA0KSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMikpID4+IDIpXG5cdFx0XHRwdXNoKCh0bXAgPj4gOCkgJiAweEZGKVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH1cblxuXHRcdHJldHVybiBhcnJcblx0fVxuXG5cdGZ1bmN0aW9uIHVpbnQ4VG9CYXNlNjQgKHVpbnQ4KSB7XG5cdFx0dmFyIGksXG5cdFx0XHRleHRyYUJ5dGVzID0gdWludDgubGVuZ3RoICUgMywgLy8gaWYgd2UgaGF2ZSAxIGJ5dGUgbGVmdCwgcGFkIDIgYnl0ZXNcblx0XHRcdG91dHB1dCA9IFwiXCIsXG5cdFx0XHR0ZW1wLCBsZW5ndGhcblxuXHRcdGZ1bmN0aW9uIGVuY29kZSAobnVtKSB7XG5cdFx0XHRyZXR1cm4gbG9va3VwLmNoYXJBdChudW0pXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gdHJpcGxldFRvQmFzZTY0IChudW0pIHtcblx0XHRcdHJldHVybiBlbmNvZGUobnVtID4+IDE4ICYgMHgzRikgKyBlbmNvZGUobnVtID4+IDEyICYgMHgzRikgKyBlbmNvZGUobnVtID4+IDYgJiAweDNGKSArIGVuY29kZShudW0gJiAweDNGKVxuXHRcdH1cblxuXHRcdC8vIGdvIHRocm91Z2ggdGhlIGFycmF5IGV2ZXJ5IHRocmVlIGJ5dGVzLCB3ZSdsbCBkZWFsIHdpdGggdHJhaWxpbmcgc3R1ZmYgbGF0ZXJcblx0XHRmb3IgKGkgPSAwLCBsZW5ndGggPSB1aW50OC5sZW5ndGggLSBleHRyYUJ5dGVzOyBpIDwgbGVuZ3RoOyBpICs9IDMpIHtcblx0XHRcdHRlbXAgPSAodWludDhbaV0gPDwgMTYpICsgKHVpbnQ4W2kgKyAxXSA8PCA4KSArICh1aW50OFtpICsgMl0pXG5cdFx0XHRvdXRwdXQgKz0gdHJpcGxldFRvQmFzZTY0KHRlbXApXG5cdFx0fVxuXG5cdFx0Ly8gcGFkIHRoZSBlbmQgd2l0aCB6ZXJvcywgYnV0IG1ha2Ugc3VyZSB0byBub3QgZm9yZ2V0IHRoZSBleHRyYSBieXRlc1xuXHRcdHN3aXRjaCAoZXh0cmFCeXRlcykge1xuXHRcdFx0Y2FzZSAxOlxuXHRcdFx0XHR0ZW1wID0gdWludDhbdWludDgubGVuZ3RoIC0gMV1cblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSh0ZW1wID4+IDIpXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPDwgNCkgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gJz09J1xuXHRcdFx0XHRicmVha1xuXHRcdFx0Y2FzZSAyOlxuXHRcdFx0XHR0ZW1wID0gKHVpbnQ4W3VpbnQ4Lmxlbmd0aCAtIDJdIDw8IDgpICsgKHVpbnQ4W3VpbnQ4Lmxlbmd0aCAtIDFdKVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKHRlbXAgPj4gMTApXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPj4gNCkgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKCh0ZW1wIDw8IDIpICYgMHgzRilcblx0XHRcdFx0b3V0cHV0ICs9ICc9J1xuXHRcdFx0XHRicmVha1xuXHRcdH1cblxuXHRcdHJldHVybiBvdXRwdXRcblx0fVxuXG5cdGV4cG9ydHMudG9CeXRlQXJyYXkgPSBiNjRUb0J5dGVBcnJheVxuXHRleHBvcnRzLmZyb21CeXRlQXJyYXkgPSB1aW50OFRvQmFzZTY0XG59KHR5cGVvZiBleHBvcnRzID09PSAndW5kZWZpbmVkJyA/ICh0aGlzLmJhc2U2NGpzID0ge30pIDogZXhwb3J0cykpXG4iLCJleHBvcnRzLnJlYWQgPSBmdW5jdGlvbiAoYnVmZmVyLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbVxuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIG5CaXRzID0gLTdcbiAgdmFyIGkgPSBpc0xFID8gKG5CeXRlcyAtIDEpIDogMFxuICB2YXIgZCA9IGlzTEUgPyAtMSA6IDFcbiAgdmFyIHMgPSBidWZmZXJbb2Zmc2V0ICsgaV1cblxuICBpICs9IGRcblxuICBlID0gcyAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBzID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBlTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IGUgPSBlICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgbSA9IGUgJiAoKDEgPDwgKC1uQml0cykpIC0gMSlcbiAgZSA+Pj0gKC1uQml0cylcbiAgbkJpdHMgKz0gbUxlblxuICBmb3IgKDsgbkJpdHMgPiAwOyBtID0gbSAqIDI1NiArIGJ1ZmZlcltvZmZzZXQgKyBpXSwgaSArPSBkLCBuQml0cyAtPSA4KSB7fVxuXG4gIGlmIChlID09PSAwKSB7XG4gICAgZSA9IDEgLSBlQmlhc1xuICB9IGVsc2UgaWYgKGUgPT09IGVNYXgpIHtcbiAgICByZXR1cm4gbSA/IE5hTiA6ICgocyA/IC0xIDogMSkgKiBJbmZpbml0eSlcbiAgfSBlbHNlIHtcbiAgICBtID0gbSArIE1hdGgucG93KDIsIG1MZW4pXG4gICAgZSA9IGUgLSBlQmlhc1xuICB9XG4gIHJldHVybiAocyA/IC0xIDogMSkgKiBtICogTWF0aC5wb3coMiwgZSAtIG1MZW4pXG59XG5cbmV4cG9ydHMud3JpdGUgPSBmdW5jdGlvbiAoYnVmZmVyLCB2YWx1ZSwgb2Zmc2V0LCBpc0xFLCBtTGVuLCBuQnl0ZXMpIHtcbiAgdmFyIGUsIG0sIGNcbiAgdmFyIGVMZW4gPSBuQnl0ZXMgKiA4IC0gbUxlbiAtIDFcbiAgdmFyIGVNYXggPSAoMSA8PCBlTGVuKSAtIDFcbiAgdmFyIGVCaWFzID0gZU1heCA+PiAxXG4gIHZhciBydCA9IChtTGVuID09PSAyMyA/IE1hdGgucG93KDIsIC0yNCkgLSBNYXRoLnBvdygyLCAtNzcpIDogMClcbiAgdmFyIGkgPSBpc0xFID8gMCA6IChuQnl0ZXMgLSAxKVxuICB2YXIgZCA9IGlzTEUgPyAxIDogLTFcbiAgdmFyIHMgPSB2YWx1ZSA8IDAgfHwgKHZhbHVlID09PSAwICYmIDEgLyB2YWx1ZSA8IDApID8gMSA6IDBcblxuICB2YWx1ZSA9IE1hdGguYWJzKHZhbHVlKVxuXG4gIGlmIChpc05hTih2YWx1ZSkgfHwgdmFsdWUgPT09IEluZmluaXR5KSB7XG4gICAgbSA9IGlzTmFOKHZhbHVlKSA/IDEgOiAwXG4gICAgZSA9IGVNYXhcbiAgfSBlbHNlIHtcbiAgICBlID0gTWF0aC5mbG9vcihNYXRoLmxvZyh2YWx1ZSkgLyBNYXRoLkxOMilcbiAgICBpZiAodmFsdWUgKiAoYyA9IE1hdGgucG93KDIsIC1lKSkgPCAxKSB7XG4gICAgICBlLS1cbiAgICAgIGMgKj0gMlxuICAgIH1cbiAgICBpZiAoZSArIGVCaWFzID49IDEpIHtcbiAgICAgIHZhbHVlICs9IHJ0IC8gY1xuICAgIH0gZWxzZSB7XG4gICAgICB2YWx1ZSArPSBydCAqIE1hdGgucG93KDIsIDEgLSBlQmlhcylcbiAgICB9XG4gICAgaWYgKHZhbHVlICogYyA+PSAyKSB7XG4gICAgICBlKytcbiAgICAgIGMgLz0gMlxuICAgIH1cblxuICAgIGlmIChlICsgZUJpYXMgPj0gZU1heCkge1xuICAgICAgbSA9IDBcbiAgICAgIGUgPSBlTWF4XG4gICAgfSBlbHNlIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgbSA9ICh2YWx1ZSAqIGMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gZSArIGVCaWFzXG4gICAgfSBlbHNlIHtcbiAgICAgIG0gPSB2YWx1ZSAqIE1hdGgucG93KDIsIGVCaWFzIC0gMSkgKiBNYXRoLnBvdygyLCBtTGVuKVxuICAgICAgZSA9IDBcbiAgICB9XG4gIH1cblxuICBmb3IgKDsgbUxlbiA+PSA4OyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBtICYgMHhmZiwgaSArPSBkLCBtIC89IDI1NiwgbUxlbiAtPSA4KSB7fVxuXG4gIGUgPSAoZSA8PCBtTGVuKSB8IG1cbiAgZUxlbiArPSBtTGVuXG4gIGZvciAoOyBlTGVuID4gMDsgYnVmZmVyW29mZnNldCArIGldID0gZSAmIDB4ZmYsIGkgKz0gZCwgZSAvPSAyNTYsIGVMZW4gLT0gOCkge31cblxuICBidWZmZXJbb2Zmc2V0ICsgaSAtIGRdIHw9IHMgKiAxMjhcbn1cbiIsIlxuLyoqXG4gKiBpc0FycmF5XG4gKi9cblxudmFyIGlzQXJyYXkgPSBBcnJheS5pc0FycmF5O1xuXG4vKipcbiAqIHRvU3RyaW5nXG4gKi9cblxudmFyIHN0ciA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmc7XG5cbi8qKlxuICogV2hldGhlciBvciBub3QgdGhlIGdpdmVuIGB2YWxgXG4gKiBpcyBhbiBhcnJheS5cbiAqXG4gKiBleGFtcGxlOlxuICpcbiAqICAgICAgICBpc0FycmF5KFtdKTtcbiAqICAgICAgICAvLyA+IHRydWVcbiAqICAgICAgICBpc0FycmF5KGFyZ3VtZW50cyk7XG4gKiAgICAgICAgLy8gPiBmYWxzZVxuICogICAgICAgIGlzQXJyYXkoJycpO1xuICogICAgICAgIC8vID4gZmFsc2VcbiAqXG4gKiBAcGFyYW0ge21peGVkfSB2YWxcbiAqIEByZXR1cm4ge2Jvb2x9XG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBpc0FycmF5IHx8IGZ1bmN0aW9uICh2YWwpIHtcbiAgcmV0dXJuICEhIHZhbCAmJiAnW29iamVjdCBBcnJheV0nID09IHN0ci5jYWxsKHZhbCk7XG59O1xuIiwibW9kdWxlLmV4cG9ydHM9e1xuICAgIFwidmVyc2lvblwiOiBcIlwiXG59XG4iLCIvKipcbiAqIEVwaWNlbnRlciBKYXZhc2NyaXB0IGxpYnJhcmllc1xuICogdjwlPSB2ZXJzaW9uICU+XG4gKiBodHRwczovL2dpdGh1Yi5jb20vZm9yaW8vZXBpY2VudGVyLWpzLWxpYnNcbiAqL1xuXG52YXIgRiA9IHtcbiAgICB1dGlsOiB7fSxcbiAgICBmYWN0b3J5OiB7fSxcbiAgICB0cmFuc3BvcnQ6IHt9LFxuICAgIHN0b3JlOiB7fSxcbiAgICBzZXJ2aWNlOiB7fSxcbiAgICBtYW5hZ2VyOiB7XG4gICAgICAgIHN0cmF0ZWd5OiB7fVxuICAgIH0sXG5cbn07XG5cbkYudXRpbC5xdWVyeSA9IHJlcXVpcmUoJy4vdXRpbC9xdWVyeS11dGlsJyk7XG5GLnV0aWwubWFrZVNlcXVlbmNlID0gcmVxdWlyZSgnLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbkYudXRpbC5ydW4gPSByZXF1aXJlKCcuL3V0aWwvcnVuLXV0aWwnKTtcbkYudXRpbC5jbGFzc0Zyb20gPSByZXF1aXJlKCcuL3V0aWwvaW5oZXJpdCcpO1xuXG5GLmZhY3RvcnkuVHJhbnNwb3J0ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuRi50cmFuc3BvcnQuQWpheCA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0L2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcblxuRi5zZXJ2aWNlLlVSTCA9IHJlcXVpcmUoJy4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbkYuc2VydmljZS5Db25maWcgPSByZXF1aXJlKCcuL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuUnVuID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkZpbGUgPSByZXF1aXJlKCcuL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuVmFyaWFibGVzID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkRhdGEgPSByZXF1aXJlKCcuL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkF1dGggPSByZXF1aXJlKCcuL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLldvcmxkID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuU3RhdGUgPSByZXF1aXJlKCcuL3NlcnZpY2Uvc3RhdGUtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Vc2VyID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VzZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5NZW1iZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvbWVtYmVyLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuQXNzZXQgPSByZXF1aXJlKCcuL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXInKTtcblxuRi5zdG9yZS5Db29raWUgPSByZXF1aXJlKCcuL3N0b3JlL2Nvb2tpZS1zdG9yZScpO1xuRi5mYWN0b3J5LlN0b3JlID0gcmVxdWlyZSgnLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG5cbkYubWFuYWdlci5TY2VuYXJpb01hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3NjZW5hcmlvLW1hbmFnZXInKTtcbkYubWFuYWdlci5SdW5NYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9hdXRoLW1hbmFnZXInKTtcbkYubWFuYWdlci5Xb3JsZE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3dvcmxkLW1hbmFnZXInKTtcblxuRi5tYW5hZ2VyLnN0cmF0ZWd5WydhbHdheXMtbmV3J10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2Fsd2F5cy1uZXctc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnY29uZGl0aW9uYWwtY3JlYXRpb24nXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneS5pZGVudGl0eSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvaWRlbnRpdHktc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLW1pc3NpbmcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLW1pc3Npbmctc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLW1pc3NpbmcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLW1pc3Npbmctc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLXBlcnNpc3RlZCddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5Jyk7XG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ25ldy1pZi1pbml0aWFsaXplZCddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtaW5pdGlhbGl6ZWQtc3RyYXRlZ3knKTtcblxuRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyJyk7XG5GLnNlcnZpY2UuQ2hhbm5lbCA9IHJlcXVpcmUoJy4vc2VydmljZS9jaGFubmVsLXNlcnZpY2UnKTtcblxuRi52ZXJzaW9uID0gJzwlPSB2ZXJzaW9uICU+JztcbkYuYXBpID0gcmVxdWlyZSgnLi9hcGktdmVyc2lvbi5qc29uJyk7XG5cbmdsb2JhbC5GID0gRjtcbm1vZHVsZS5leHBvcnRzID0gRjtcbiIsIi8qKlxuKiAjIyBBdXRob3JpemF0aW9uIE1hbmFnZXJcbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byBtYW5hZ2UgdXNlciBhdXRoZW50aWNhdGlvbiAobG9nZ2luZyBpbiBhbmQgb3V0KSBhbmQgYXV0aG9yaXphdGlvbiAoa2VlcGluZyB0cmFjayBvZiB0b2tlbnMsIHNlc3Npb25zLCBhbmQgZ3JvdXBzKSBmb3IgcHJvamVjdHMuXG4qXG4qIFRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgaXMgbW9zdCB1c2VmdWwgZm9yIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSkgd2l0aCBhbiBhY2Nlc3MgbGV2ZWwgb2YgW0F1dGhlbnRpY2F0ZWRdKC4uLy4uLy4uL2dsb3NzYXJ5LyNhY2Nlc3MpLiBUaGVzZSBwcm9qZWN0cyBhcmUgYWNjZXNzZWQgYnkgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSB3aG8gYXJlIG1lbWJlcnMgb2Ygb25lIG9yIG1vcmUgW2dyb3Vwc10oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykuXG4qXG4qICMjIyNVc2luZyB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyXG4qXG4qIFRvIHVzZSB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdC4gVGhlbiwgbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQ6XG4qXG4qICAgICAgIHZhciBhdXRoTWdyID0gbmV3IEYubWFuYWdlci5BdXRoTWFuYWdlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB1c2VyTmFtZTogJ2VuZHVzZXIxJyxcbiogICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnXG4qICAgICAgIH0pO1xuKiAgICAgICBhdXRoTWdyLmxvZ2luKCkudGhlbihmdW5jdGlvbiAoKSB7XG4qICAgICAgICAgICBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiogICAgICAgfSk7XG4qXG4qXG4qIFRoZSBgb3B0aW9uc2Agb2JqZWN0IHBhc3NlZCB0byB0aGUgYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCBjYWxsIGNhbiBpbmNsdWRlOlxuKlxuKiAgICogYGFjY291bnRgOiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiogICAqIGB1c2VyTmFtZWA6IEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi5cbiogICAqIGBwYXNzd29yZGA6IFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGUgcHJvamVjdCB0byBsb2cgdGhpcyB1c2VyIGludG8uIE9wdGlvbmFsLlxuKiAgICogYGdyb3VwSWRgOiBJZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgZW5kIHVzZXJzIGlmIHRoZSBgcHJvamVjdGAgaXMgc3BlY2lmaWVkLlxuKlxuKiBJZiB5b3UgcHJlZmVyIHN0YXJ0aW5nIGZyb20gYSB0ZW1wbGF0ZSwgdGhlIEVwaWNlbnRlciBKUyBMaWJzIFtMb2dpbiBDb21wb25lbnRdKC4uLy4uLyNjb21wb25lbnRzKSB1c2VzIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgYXMgd2VsbC4gVGhpcyBzYW1wbGUgSFRNTCBwYWdlIChhbmQgYXNzb2NpYXRlZCBDU1MgYW5kIEpTIGZpbGVzKSBwcm92aWRlcyBhIGxvZ2luIGZvcm0gZm9yIHRlYW0gbWVtYmVycyBhbmQgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdC4gSXQgYWxzbyBpbmNsdWRlcyBhIGdyb3VwIHNlbGVjdG9yIGZvciBlbmQgdXNlcnMgdGhhdCBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBncm91cHMuXG4qL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgQXV0aEFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2F1dGgtYXBpLXNlcnZpY2UnKTtcbnZhciBNZW1iZXJBZGFwdGVyID0gcmVxdWlyZSgnLi4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBCdWZmZXIgPSByZXF1aXJlKCdidWZmZXInKS5CdWZmZXI7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogV2hlcmUgdG8gc3RvcmUgdXNlciBhY2Nlc3MgdG9rZW5zIGZvciB0ZW1wb3JhcnkgYWNjZXNzLiBEZWZhdWx0cyB0byBzdG9yaW5nIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLlxuICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICovXG4gICAgc3RvcmU6IHsgc3luY2hyb25vdXM6IHRydWUgfVxufTtcblxudmFyIEVQSV9DT09LSUVfS0VZID0ga2V5TmFtZXMuRVBJX0NPT0tJRV9LRVk7XG52YXIgRVBJX1NFU1NJT05fS0VZID0ga2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZO1xudmFyIHN0b3JlO1xudmFyIHRva2VuO1xudmFyIHNlc3Npb247XG5cbmZ1bmN0aW9uIHNhdmVTZXNzaW9uKHVzZXJJbmZvLCBzdG9yZSkge1xuICAgIHZhciBzZXJpYWxpemVkID0gSlNPTi5zdHJpbmdpZnkodXNlckluZm8pO1xuICAgIHN0b3JlLnNldChFUElfU0VTU0lPTl9LRVksIHNlcmlhbGl6ZWQpO1xuXG4gICAgLy9qc2hpbnQgY2FtZWxjYXNlOiBmYWxzZVxuICAgIC8vanNjczpkaXNhYmxlXG4gICAgc3RvcmUuc2V0KEVQSV9DT09LSUVfS0VZLCB1c2VySW5mby5hdXRoX3Rva2VuKTtcbn1cblxuZnVuY3Rpb24gZ2V0U2Vzc2lvbihzdG9yZSkge1xuICAgIHZhciBzZXNzaW9uID0gc3RvcmUuZ2V0KEVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9JztcbiAgICByZXR1cm4gSlNPTi5wYXJzZShzZXNzaW9uKTtcbn1cblxuZnVuY3Rpb24gQXV0aE1hbmFnZXIob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2UodGhpcy5vcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIHRoaXMuaXNMb2NhbCA9IHVybENvbmZpZy5pc0xvY2FsaG9zdCgpO1xuXG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB0aGlzLm9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICAvLyBudWxsIG1pZ2h0IHNwZWNpZmllZCB0byBkaXNhYmxlIHByb2plY3QgZmlsdGVyaW5nXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wcm9qZWN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdGhpcy5zdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh0aGlzLm9wdGlvbnMuc3RvcmUpO1xuICAgIHNlc3Npb24gPSBnZXRTZXNzaW9uKHRoaXMuc3RvcmUpO1xuICAgIHRva2VuID0gdGhpcy5zdG9yZS5nZXQoRVBJX0NPT0tJRV9LRVkpIHx8ICcnO1xuICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAvL2pzY3M6ZGlzYWJsZVxuICAgIHRoaXMuYXV0aEFkYXB0ZXIgPSBuZXcgQXV0aEFkYXB0ZXIodGhpcy5vcHRpb25zLCB7IHRva2VuOiBzZXNzaW9uLmF1dGhfdG9rZW4gfSk7XG59XG5cbnZhciBfZmluZFVzZXJJbkdyb3VwID0gZnVuY3Rpb24gKG1lbWJlcnMsIGlkKSB7XG4gICAgZm9yICh2YXIgaiA9IDA7IGo8bWVtYmVycy5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAobWVtYmVyc1tqXS51c2VySWQgPT09IGlkKSB7XG4gICAgICAgICAgICByZXR1cm4gbWVtYmVyc1tqXTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgcmV0dXJuIG51bGw7XG59O1xuXG5BdXRoTWFuYWdlci5wcm90b3R5cGUgPSAkLmV4dGVuZChBdXRoTWFuYWdlci5wcm90b3R5cGUsIHtcblxuICAgIC8qKlxuICAgICogTG9ncyB1c2VyIGluLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dpbih7XG4gICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgKiAgICAgICAgICAgdXNlck5hbWU6ICdlbmR1c2VyMScsXG4gICAgKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiAgICAqICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gZXhhY3RseSBvbmUgZ3JvdXBcbiAgICAqICAgICAgICAgICAgICAgLy8gKG9yIGlmIHRoZSBsb2dpbigpIGNhbGwgaXMgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGUgZ3JvdXAgaWQpXG4gICAgKiAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIGhlcmVcbiAgICAqICAgICAgICAgICB9KVxuICAgICogICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIG11bHRpcGxlIGdyb3VwcyxcbiAgICAqICAgICAgICAgICAgICAgLy8gdGhlIGxvZ2luKCkgY2FsbCBmYWlsc1xuICAgICogICAgICAgICAgICAgICAvLyBhbmQgcmV0dXJucyBhbGwgZ3JvdXBzIG9mIHdoaWNoIHRoZSB1c2VyIGlzIGEgbWVtYmVyXG4gICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IHN0YXR1c09iai51c2VyR3JvdXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5uYW1lLCBzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5ncm91cElkKTtcbiAgICAqICAgICAgICAgICAgICAgfVxuICAgICogICAgICAgICAgIH0pO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLiBJZiBub3QgcGFzc2VkIGluIHdoZW4gY3JlYXRpbmcgYW4gaW5zdGFuY2Ugb2YgdGhlIG1hbmFnZXIgKGBGLm1hbmFnZXIuQXV0aE1hbmFnZXIoKWApLCB0aGVzZSBvcHRpb25zIHNob3VsZCBpbmNsdWRlOlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmFjY291bnRgIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnVzZXJOYW1lYCBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMucGFzc3dvcmRgIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5wcm9qZWN0YCAoT3B0aW9uYWwpIFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhlIHByb2plY3QgdG8gbG9nIHRoaXMgdXNlciBpbnRvLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpZiB0aGUgYHByb2plY3RgIGlzIHNwZWNpZmllZCBhbmQgaWYgdGhlIGVuZCB1c2VycyBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3RoZXJ3aXNlIG9wdGlvbmFsLlxuICAgICovXG4gICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AsIGVycm9yOiAkLm5vb3AgfSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuICAgICAgICB2YXIgb3V0RXJyb3IgPSBhZGFwdGVyT3B0aW9ucy5lcnJvcjtcbiAgICAgICAgdmFyIGdyb3VwSWQgPSBhZGFwdGVyT3B0aW9ucy5ncm91cElkO1xuXG4gICAgICAgIHZhciBhY2NvdW50TmFtZSA9IChvcHRpb25zICYmIG9wdGlvbnMuYWNjb3VudCkgPyBvcHRpb25zLmFjY291bnQgOiB0aGlzLm9wdGlvbnMuYWNjb3VudDtcbiAgICAgICAgdmFyIHByb2plY3ROYW1lID0gKG9wdGlvbnMgJiYgb3B0aW9ucy5wcm9qZWN0KSA/IG9wdGlvbnMucHJvamVjdCA6IHRoaXMub3B0aW9ucy5wcm9qZWN0O1xuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuc3RvcmUucm9vdCA9PT0gdW5kZWZpbmVkICYmIGFjY291bnROYW1lICYmIHByb2plY3ROYW1lKSB7XG4gICAgICAgICAgICB0aGlzLnN0b3JlLnNlcnZpY2VPcHRpb25zLnJvb3QgPSB0aGlzLmlzTG9jYWwgPyAnLycgOiAnL2FwcC8nICsgYWNjb3VudE5hbWUgKyAnLycgKyBwcm9qZWN0TmFtZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBkZWNvZGVUb2tlbiA9IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgICAgdmFyIGVuY29kZWQgPSB0b2tlbi5zcGxpdCgnLicpWzFdO1xuICAgICAgICAgICAgd2hpbGUgKGVuY29kZWQubGVuZ3RoICUgNCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIGVuY29kZWQgKz0gJz0nO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZGVjb2RlID0gd2luZG93LmF0b2IgPyB3aW5kb3cuYXRvYiA6IGZ1bmN0aW9uIChlbmNvZGVkKSB7IHJldHVybiBuZXcgQnVmZmVyKGVuY29kZWQsICdiYXNlNjQnKS50b1N0cmluZygnYXNjaWknKTsgfTtcblxuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGVjb2RlKGVuY29kZWQpKTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgaGFuZGxlR3JvdXBFcnJvciA9IGZ1bmN0aW9uIChtZXNzYWdlLCBzdGF0dXNDb2RlLCBkYXRhKSB7XG4gICAgICAgICAgICAvLyBsb2dvdXQgdGhlIHVzZXIgc2luY2UgaXQncyBpbiBhbiBpbnZhbGlkIHN0YXRlIHdpdGggbm8gZ3JvdXAgc2VsZWN0ZWRcbiAgICAgICAgICAgIF90aGlzLmxvZ291dCgpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBlcnJvciA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkYXRhLCB7IHN0YXR1c1RleHQ6IG1lc3NhZ2UsIHN0YXR1czogc3RhdHVzQ29kZSB9KTtcbiAgICAgICAgICAgICAgICAkZC5yZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZVN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAgICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgICAgICB0b2tlbiA9IHJlc3BvbnNlLmFjY2Vzc190b2tlbjtcbiAgICAgICAgICAgIHZhciB1c2VySW5mbyA9IGRlY29kZVRva2VuKHRva2VuKTtcbiAgICAgICAgICAgIHZhciB1c2VyR3JvdXBPcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIGFkYXB0ZXJPcHRpb25zLCB7IHN1Y2Nlc3M6ICQubm9vcCwgdG9rZW46IHRva2VuIH0pO1xuICAgICAgICAgICAgX3RoaXMuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogdXNlckluZm8udXNlcl9pZCwgdG9rZW46IHRva2VuIH0sIHVzZXJHcm91cE9wdHMpLmRvbmUoIGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGEgPSB7YXV0aDogcmVzcG9uc2UsIHVzZXI6IHVzZXJJbmZvLCB1c2VyR3JvdXBzOiBtZW1iZXJJbmZvLCBncm91cFNlbGVjdGlvbjoge30gfTtcblxuICAgICAgICAgICAgICAgIHZhciBzZXNzaW9uSW5mbyA9IHtcbiAgICAgICAgICAgICAgICAgICAgJ2F1dGhfdG9rZW4nOiB0b2tlbixcbiAgICAgICAgICAgICAgICAgICAgJ2FjY291bnQnOiBhZGFwdGVyT3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgICAgICAncHJvamVjdCc6IGFkYXB0ZXJPcHRpb25zLnByb2plY3QsXG4gICAgICAgICAgICAgICAgICAgICd1c2VySWQnOiB1c2VySW5mby51c2VyX2lkXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAvLyBUaGUgZ3JvdXAgaXMgbm90IHJlcXVpcmVkIGlmIHRoZSB1c2VyIGlzIG5vdCBsb2dnaW5nIGludG8gYSBwcm9qZWN0XG4gICAgICAgICAgICAgICAgaWYgKCFhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHNhdmVTZXNzaW9uKHNlc3Npb25JbmZvLCBfdGhpcy5zdG9yZSk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBncm91cCA9IG51bGw7XG4gICAgICAgICAgICAgICAgaWYgKG1lbWJlckluZm8ubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoZSB1c2VyIGhhcyBubyBncm91cHMgYXNzb2NpYXRlZCBpbiB0aGlzIGFjY291bnQnLCA0MDEsIGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZW1iZXJJbmZvLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTZWxlY3QgdGhlIG9ubHkgZ3JvdXBcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBtZW1iZXJJbmZvWzBdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobWVtYmVySW5mby5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChncm91cElkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmlsdGVyZWRHcm91cHMgPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKHJlc0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc0dyb3VwLmdyb3VwSWQgPT09IGdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gZmlsdGVyZWRHcm91cHMubGVuZ3RoID09PSAxID8gZmlsdGVyZWRHcm91cHNbMF0gOiBudWxsO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBncm91cFNlbGVjdGlvbiA9IGdyb3VwLmdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEuZ3JvdXBTZWxlY3Rpb25bYWRhcHRlck9wdGlvbnMucHJvamVjdF0gPSBncm91cFNlbGVjdGlvbjtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNlc3Npb25JbmZvV2l0aEdyb3VwID0gJC5leHRlbmQoe30sIHNlc3Npb25JbmZvLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAnZ3JvdXBJZCc6IGdyb3VwLmdyb3VwSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAnZ3JvdXBOYW1lJzogZ3JvdXAubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICdpc0ZhYyc6IF9maW5kVXNlckluR3JvdXAoZ3JvdXAubWVtYmVycywgdXNlckluZm8udXNlcl9pZCkucm9sZSA9PT0gJ2ZhY2lsaXRhdG9yJ1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgc2F2ZVNlc3Npb24oc2Vzc2lvbkluZm9XaXRoR3JvdXAsIF90aGlzLnN0b3JlKTtcbiAgICAgICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoaXMgdXNlciBpcyBhc3NvY2lhdGVkIHdpdGggbW9yZSB0aGFuIG9uZSBncm91cC4gUGxlYXNlIHNwZWNpZnkgYSBncm91cCBpZCB0byBsb2cgaW50byBhbmQgdHJ5IGFnYWluJywgNDAzLCBkYXRhKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGhhbmRsZVN1Y2Nlc3M7XG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vIFRyeSB0byBsb2dpbiBhcyBhIHN5c3RlbSB1c2VyXG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuYWNjb3VudCA9IG51bGw7XG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuZXJyb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdChyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIF90aGlzLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuYXV0aEFkYXB0ZXIubG9naW4oYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAqIExvZ3MgdXNlciBvdXQuXG4gICAgKlxuICAgICogKipFeGFtcGxlKipcbiAgICAqXG4gICAgKiAgICAgICBhdXRoTWdyLmxvZ291dCgpO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICovXG4gICAgbG9nb3V0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgYWRhcHRlck9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHRva2VuOiB0b2tlbiB9LCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciByZW1vdmVDb29raWVGbiA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgc3RvcmUucmVtb3ZlKEVQSV9DT09LSUVfS0VZLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICBzdG9yZS5yZW1vdmUoRVBJX1NFU1NJT05fS0VZLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICB0b2tlbiA9ICcnO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhBZGFwdGVyLmxvZ291dChhZGFwdGVyT3B0aW9ucykuZG9uZShyZW1vdmVDb29raWVGbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGV4aXN0aW5nIHVzZXIgYWNjZXNzIHRva2VuIGlmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluLiBPdGhlcndpc2UsIGxvZ3MgdGhlIHVzZXIgaW4sIGNyZWF0aW5nIGEgbmV3IHVzZXIgYWNjZXNzIHRva2VuLCBhbmQgcmV0dXJucyB0aGUgbmV3IHRva2VuLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBhdXRoTWdyLmdldFRva2VuKClcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coJ015IHRva2VuIGlzICcsIHRva2VuKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgaWYgKHRva2VuKSB7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKHRva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICogICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKylcbiAgICAgKiAgICAgICAgICAgICAgICAgIHsgY29uc29sZS5sb2coZ3JvdXBzW2ldLm5hbWUpOyB9XG4gICAgICogICAgICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIHBhcnRpY3VsYXIgdXNlclxuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHt1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB0b2tlbjogc2F2ZWRQcm9qQWNjZXNzVG9rZW4gfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcGFyYW1zYCBPYmplY3Qgd2l0aCBhIHVzZXJJZCBhbmQgdG9rZW4gcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSB1c2VySWQuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBPdGhlcndpc2UsIHBhc3MgYSBzdHJpbmcuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGBwYXJhbXMudG9rZW5gIFRoZSBhdXRob3JpemF0aW9uIGNyZWRlbnRpYWxzIChhY2Nlc3MgdG9rZW4pIHRvIHVzZSBmb3IgY2hlY2tpbmcgdGhlIGdyb3VwcyBmb3IgdGhpcyB1c2VyLiBJZiBsb29raW5nIHVwIGdyb3VwcyBmb3IgdGhlIGN1cnJlbnRseSBsb2dnZWQgaW4gdXNlciwgdGhpcyBpcyBpbiB0aGUgc2Vzc2lvbiBpbmZvcm1hdGlvbi4gQSB0ZWFtIG1lbWJlcidzIHRva2VuIG9yIGEgcHJvamVjdCBhY2Nlc3MgdG9rZW4gY2FuIGFjY2VzcyBhbGwgdGhlIGdyb3VwcyBmb3IgYWxsIGVuZCB1c2VycyBpbiB0aGUgdGVhbSBvciBwcm9qZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKi9cbiAgICBnZXRVc2VyR3JvdXBzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHsgc3VjY2VzczogJC5ub29wIH0sIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAobWVtYmVySW5mbykge1xuICAgICAgICAgICAgLy8gVGhlIG1lbWJlciBBUEkgaXMgYXQgdGhlIGFjY291bnQgc2NvcGUsIHdlIGZpbHRlciBieSBwcm9qZWN0XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICAgICAgICAgIG1lbWJlckluZm8gPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBncm91cC5wcm9qZWN0ID09PSBhZGFwdGVyT3B0aW9ucy5wcm9qZWN0O1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRTdWNjZXNzLmFwcGx5KHRoaXMsIFttZW1iZXJJbmZvXSk7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKG1lbWJlckluZm8pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBtZW1iZXJBZGFwdGVyID0gbmV3IE1lbWJlckFkYXB0ZXIoeyB0b2tlbjogcGFyYW1zLnRva2VuIH0pO1xuICAgICAgICBtZW1iZXJBZGFwdGVyLmdldEdyb3Vwc0ZvclVzZXIocGFyYW1zLCBhZGFwdGVyT3B0aW9ucykuZmFpbCgkZC5yZWplY3QpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHNlc3Npb24gaW5mb3JtYXRpb24gZm9yIHRoZSBjdXJyZW50IHVzZXIsIGluY2x1ZGluZyB0aGUgYHVzZXJJZGAsIGBhY2NvdW50YCwgYHByb2plY3RgLCBgZ3JvdXBJZGAsIGBncm91cE5hbWVgLCBgaXNGYWNgICh3aGV0aGVyIHRoZSBlbmQgdXNlciBpcyBhIGZhY2lsaXRhdG9yIG9mIHRoaXMgZ3JvdXApLCBhbmQgYGF1dGhfdG9rZW5gICh1c2VyIGFjY2VzcyB0b2tlbikuXG4gICAgICpcbiAgICAgKiAqSW1wb3J0YW50KjogVGhpcyBtZXRob2QgaXMgc3luY2hyb25vdXMuIFRoZSBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHJldHVybmVkIGltbWVkaWF0ZWx5IGluIGFuIG9iamVjdDsgbm8gY2FsbGJhY2tzIG9yIHByb21pc2VzIGFyZSBuZWVkZWQuXG4gICAgICpcbiAgICAgKiBCeSBkZWZhdWx0LCBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHN0b3JlZCBpbiBhIGNvb2tpZSBpbiB0aGUgYnJvd3Nlci4gWW91IGNhbiBjaGFuZ2UgdGhpcyB3aXRoIHRoZSBgc3RvcmVgIGNvbmZpZ3VyYXRpb24gb3B0aW9uLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm86IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiBnZXRTZXNzaW9uKHRoaXMuc3RvcmUsIG9wdGlvbnMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEF1dGhNYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2hhbm5lbCA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlJyk7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgYXJvdW5kIHRoZSBkZWZhdWx0IFtjb21ldGQgSmF2YVNjcmlwdCBsaWJyYXJ5XShodHRwOi8vZG9jcy5jb21ldGQub3JnLzIvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCksIGAkLmNvbWV0ZGAuIEl0IHByb3ZpZGVzIGEgZmV3IG5pY2UgZmVhdHVyZXMgdGhhdCBgJC5jb21ldGRgIGRvZXNuJ3QsIGluY2x1ZGluZzpcbiAqXG4gKiAqIEF1dG9tYXRpYyByZS1zdWJzY3JpcHRpb24gdG8gY2hhbm5lbHMgaWYgeW91IGxvc2UgeW91ciBjb25uZWN0aW9uXG4gKiAqIE9ubGluZSAvIE9mZmxpbmUgbm90aWZpY2F0aW9uc1xuICogKiAnRXZlbnRzJyBmb3IgY29tZXRkIG5vdGlmaWNhdGlvbnMgKGluc3RlYWQgb2YgaGF2aW5nIHRvIGxpc3RlbiBvbiBzcGVjaWZpYyBtZXRhIGNoYW5uZWxzKVxuICpcbiAqIFdoaWxlIHlvdSBjYW4gd29yayBkaXJlY3RseSB3aXRoIHRoZSBDaGFubmVsIE1hbmFnZXIgdGhyb3VnaCBOb2RlLmpzIChmb3IgZXhhbXBsZSwgYHJlcXVpcmUoJ21hbmFnZXIvY2hhbm5lbC1tYW5hZ2VyJylgKSAtLSBvciBldmVuIHdvcmsgZGlyZWN0bHkgd2l0aCBgJC5jb21ldGRgIGFuZCBFcGljZW50ZXIncyB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIC0tIG1vc3Qgb2Z0ZW4gaXQgd2lsbCBiZSBlYXNpZXN0IHRvIHdvcmsgd2l0aCB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKS4gVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIHRoYXQgaW5zdGFudGlhdGVzIGEgQ2hhbm5lbCBNYW5hZ2VyIHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgTWFuYWdlci4gKFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLilcbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgTWFuYWdlciBpbiBjbGllbnQtc2lkZSBKYXZhU2NyaXB0LCBpbnN0YW50aWF0ZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSwgZ2V0IHRoZSBjaGFubmVsLCB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gKlxuICogICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAqICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgTWFuYWdlci4gQmVzaWRlcyB0aGUgY29tbW9uIG9wdGlvbnMgbGlzdGVkIGhlcmUsIHNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIG90aGVyIHN1cHBvcnRlZCBvcHRpb25zLlxuICogKiBgb3B0aW9ucy51cmxgIFRoZSBDb21ldGQgZW5kcG9pbnQgVVJMLlxuICogKiBgb3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkYCBXaGV0aGVyIHdlYnNvY2tldCBzdXBwb3J0IGlzIGFjdGl2ZSAoYm9vbGVhbikuXG4gKiAqIGBvcHRpb25zLmNoYW5uZWxgIE90aGVyIGRlZmF1bHRzIHRvIHBhc3Mgb24gdG8gaW5zdGFuY2VzIG9mIHRoZSB1bmRlcmx5aW5nIENoYW5uZWwgU2VydmljZS4gU2VlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pIGZvciBkZXRhaWxzLlxuICpcbiAqL1xudmFyIENoYW5uZWxNYW5hZ2VyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICBpZiAoISQuY29tZXRkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tZXRkIGxpYnJhcnkgbm90IGZvdW5kLiBQbGVhc2UgaW5jbHVkZSBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy51cmwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhbiB1cmwgZm9yIHRoZSBjb21ldGQgc2VydmVyJyk7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbG9nIGxldmVsIGZvciB0aGUgY2hhbm5lbCAobG9ncyB0byBjb25zb2xlKS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGxvZ0xldmVsOiAnaW5mbycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlLiBEZWZhdWx0cyB0byBgZmFsc2VgOyBFcGljZW50ZXIgZG9lc24ndCBjdXJyZW50bHkgc3VwcG9ydCBjb21tdW5pY2F0aW9uIHRocm91Z2ggd2Vic29ja2V0cy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICB3ZWJzb2NrZXRFbmFibGVkOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogSWYgZmFsc2UgZWFjaCBpbnN0YW5jZSBvZiBDaGFubmVsIHdpbGwgaGF2ZSBhIHNlcGFyYXRlIGNvbWV0ZCBjb25uZWN0aW9uIHRvIHNlcnZlciwgd2hpY2ggY291bGQgYmUgbm9pc3kuIFNldCB0byB0cnVlIHRvIHJlLXVzZSB0aGUgc2FtZSBjb25uZWN0aW9uIGFjcm9zcyBpbnN0YW5jZXMuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2hhcmVDb25uZWN0aW9uOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLyksIHdoaWNoIGFyZSBjcmVhdGVkIHRocm91Z2ggYGdldENoYW5uZWwoKWAuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBjaGFubmVsOiB7XG5cbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMgPSBbXTtcbiAgICB0aGlzLm9wdGlvbnMgPSBkZWZhdWx0Q29tZXRPcHRpb25zO1xuXG4gICAgaWYgKGRlZmF1bHRDb21ldE9wdGlvbnMuc2hhcmVDb25uZWN0aW9uICYmIENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkKSB7XG4gICAgICAgIHRoaXMuY29tZXRkID0gQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQ7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICB2YXIgY29tZXRkID0gbmV3ICQuQ29tZXRkKCk7XG4gICAgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQgPSBjb21ldGQ7XG5cbiAgICBjb21ldGQud2Vic29ja2V0RW5hYmxlZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMud2Vic29ja2V0RW5hYmxlZDtcblxuICAgIHRoaXMuaXNDb25uZWN0ZWQgPSBmYWxzZTtcbiAgICB2YXIgY29ubmVjdGlvbkJyb2tlbiA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignZGlzY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIGNvbm5lY3Rpb25TdWNjZWVkZWQgPSBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIoJ2Nvbm5lY3QnLCBtZXNzYWdlKTtcbiAgICB9O1xuICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICBjb21ldGQuY29uZmlndXJlKGRlZmF1bHRDb21ldE9wdGlvbnMpO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9jb25uZWN0JywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgdmFyIHdhc0Nvbm5lY3RlZCA9IHRoaXMuaXNDb25uZWN0ZWQ7XG4gICAgICAgIHRoaXMuaXNDb25uZWN0ZWQgPSAobWVzc2FnZS5zdWNjZXNzZnVsID09PSB0cnVlKTtcbiAgICAgICAgaWYgKCF3YXNDb25uZWN0ZWQgJiYgdGhpcy5pc0Nvbm5lY3RlZCkgeyAvL0Nvbm5lY3RpbmcgZm9yIHRoZSBmaXJzdCB0aW1lXG4gICAgICAgICAgICBjb25uZWN0aW9uU3VjY2VlZGVkLmNhbGwodGhpcywgbWVzc2FnZSk7XG4gICAgICAgIH0gZWxzZSBpZiAod2FzQ29ubmVjdGVkICYmICF0aGlzLmlzQ29ubmVjdGVkKSB7IC8vT25seSB0aHJvdyBkaXNjb25uZWN0ZWQgbWVzc2FnZSBmcm8gdGhlIGZpcnN0IGRpc2Nvbm5lY3QsIG5vdCBvbmNlIHBlciB0cnlcbiAgICAgICAgICAgIGNvbm5lY3Rpb25Ccm9rZW4uY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH0uYmluZCh0aGlzKSk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Rpc2Nvbm5lY3QnLCBjb25uZWN0aW9uQnJva2VuKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvaGFuZHNoYWtlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgaWYgKG1lc3NhZ2Uuc3VjY2Vzc2Z1bCkge1xuICAgICAgICAgICAgLy9odHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0X3N1YnNjcmliZS5odG1sI2phdmFzY3JpcHRfc3Vic2NyaWJlX21ldGFfY2hhbm5lbHNcbiAgICAgICAgICAgIC8vIF4gXCJkeW5hbWljIHN1YnNjcmlwdGlvbnMgYXJlIGNsZWFyZWQgKGxpa2UgYW55IG90aGVyIHN1YnNjcmlwdGlvbikgYW5kIHRoZSBhcHBsaWNhdGlvbiBuZWVkcyB0byBmaWd1cmUgb3V0IHdoaWNoIGR5bmFtaWMgc3Vic2NyaXB0aW9uIG11c3QgYmUgcGVyZm9ybWVkIGFnYWluXCJcbiAgICAgICAgICAgIGNvbWV0ZC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgJChtZS5jdXJyZW50U3Vic2NyaXB0aW9ucykuZWFjaChmdW5jdGlvbiAoaW5kZXgsIHN1YnMpIHtcbiAgICAgICAgICAgICAgICAgICAgY29tZXRkLnJlc3Vic2NyaWJlKHN1YnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vT3RoZXIgaW50ZXJlc3RpbmcgZXZlbnRzIGZvciByZWZlcmVuY2VcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3N1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3N1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWJzY3JpYmUnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCd1bnN1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvcHVibGlzaCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3B1Ymxpc2gnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3Vuc3VjY2Vzc2Z1bCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ2Vycm9yJywgbWVzc2FnZSk7XG4gICAgfSk7XG5cbiAgICBjb21ldGQuaGFuZHNoYWtlKCk7XG5cbiAgICB0aGlzLmNvbWV0ZCA9IGNvbWV0ZDtcbn07XG5cblxuQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgIHZhciBjaGFubmVsID0gY20uZ2V0Q2hhbm5lbCgpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvL0lmIHlvdSBqdXN0IHdhbnQgdG8gcGFzcyBpbiBhIHN0cmluZ1xuICAgICAgICBpZiAob3B0aW9ucyAmJiAhJC5pc1BsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAgICAgdHJhbnNwb3J0OiB0aGlzLmNvbWV0ZFxuICAgICAgICB9O1xuICAgICAgICB2YXIgY2hhbm5lbCA9IG5ldyBDaGFubmVsKCQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLm9wdGlvbnMuY2hhbm5lbCwgZGVmYXVsdHMsIG9wdGlvbnMpKTtcblxuXG4gICAgICAgIC8vV3JhcCBzdWJzIGFuZCB1bnN1YnMgc28gd2UgY2FuIHVzZSBpdCB0byByZS1hdHRhY2ggaGFuZGxlcnMgYWZ0ZXIgYmVpbmcgZGlzY29ubmVjdGVkXG4gICAgICAgIHZhciBzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHN1YmlkID0gc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyAgPSB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmNvbmNhdChzdWJpZCk7XG4gICAgICAgICAgICByZXR1cm4gc3ViaWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuXG4gICAgICAgIHZhciB1bnN1YnMgPSBjaGFubmVsLnVuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnVuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJlbW92ZWQgPSB1bnN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zW2ldLmlkID09PSByZW1vdmVkLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZW1vdmVkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlclxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIChtb3JlIGdlbmVyaWMpIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pLCB0byBpbnN0YW50aWF0ZSBpdCB3aXRoIEVwaWNlbnRlci1zcGVjaWZpYyBkZWZhdWx0cy4gSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGluY2x1ZGluZyBhIG5vdGlmaWNhdGlvbiBvciBjaGF0IGZlYXR1cmUgaW4geW91ciBwcm9qZWN0LCB1c2luZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIHByb2JhYmx5IHRoZSBlYXNpZXN0IHdheSB0byBnZXQgc3RhcnRlZC5cbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXI6IGluc3RhbnRpYXRlIGl0LCBnZXQgdGhlIGNoYW5uZWwgb2YgdGhlIHNjb3BlIHlvdSB3YW50IChbdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLCBvciBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpKSwgdGhlbiB1c2UgdGhlIGNoYW5uZWwncyBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIHN1YnNjcmliZSB0byB0b3BpY3Mgb3IgcHVibGlzaCBkYXRhIHRvIHRvcGljcy5cbiAqXG4gKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAqXG4gKiBGb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIEVwaWNlbnRlcidzIHB1c2ggY2hhbm5lbCwgc2VlIHRoZSBpbnRyb2R1Y3Rvcnkgbm90ZXMgb24gdGhlIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIHBhZ2UuXG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYHNlcnZlcmAgT2JqZWN0IHdpdGggZGV0YWlscyBhYm91dCB0aGUgRXBpY2VudGVyIHByb2plY3QgZm9yIHRoaXMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbnN0YW5jZS5cbiAqICogYHNlcnZlci5hY2NvdW50YCBUaGUgRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgc2VydmVyLnByb2plY3RgIEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICovXG5cbnZhciBDaGFubmVsTWFuYWdlciA9IHJlcXVpcmUoJy4vY2hhbm5lbC1tYW5hZ2VyJyk7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgdXJsU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlJyk7XG5cbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBzZXNzaW9uID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG52YXIgZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvciA9IGZ1bmN0aW9uICh2YWx1ZSwgc2Vzc2lvbktleU5hbWUsIHNldHRpbmdzKSB7XG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgaWYgKHNldHRpbmdzICYmIHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXSkge1xuICAgICAgICAgICAgdmFsdWUgPSBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV07XG4gICAgICAgIH0gZWxzZSBpZiAodXNlckluZm9bc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHVzZXJJbmZvW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihzZXNzaW9uS2V5TmFtZSArICcgbm90IGZvdW5kLiBQbGVhc2UgbG9nLWluIGFnYWluLCBvciBzcGVjaWZ5ICcgKyBzZXNzaW9uS2V5TmFtZSArICcgZXhwbGljaXRseScpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbn07XG52YXIgX19zdXBlciA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZTtcbnZhciBFcGljZW50ZXJDaGFubmVsTWFuYWdlciA9IGNsYXNzRnJvbShDaGFubmVsTWFuYWdlciwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcblxuICAgICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgICAgICBhY2NvdW50OiB1c2VySW5mby5hY2NvdW50LFxuICAgICAgICAgICAgcHJvamVjdDogdXNlckluZm8ucHJvamVjdCxcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIHVzZXJJbmZvLCBvcHRpb25zKTtcblxuICAgICAgICB2YXIgdXJsT3B0cyA9IHVybFNlcnZpY2UoZGVmYXVsdENvbWV0T3B0aW9ucy5zZXJ2ZXIpO1xuICAgICAgICBpZiAoIWRlZmF1bHRDb21ldE9wdGlvbnMudXJsKSB7XG4gICAgICAgICAgICAvL0RlZmF1bHQgZXBpY2VudGVyIGNvbWV0ZCBlbmRwb2ludFxuICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy51cmwgPSB1cmxPcHRzLnByb3RvY29sICsgJzovLycgKyB1cmxPcHRzLmhvc3QgKyAnL2NoYW5uZWwvc3Vic2NyaWJlJztcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgZGVmYXVsdENvbWV0T3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBnaXZlbiBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLiBUaGUgZ3JvdXAgbXVzdCBleGlzdCBpbiB0aGUgYWNjb3VudCAodGVhbSkgYW5kIHByb2plY3QgcHJvdmlkZWQuXG4gICAgICpcbiAgICAgKiBUaGVyZSBhcmUgbm8gbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWw7IGFsbCBtZXNzYWdlcyBhcmUgdXNlci1vcmlnaW5hdGVkLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJ2Jyb2FkY2FzdHMnLCBjYWxsYmFjayk7XG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBHcm91cCB0byBicm9hZGNhc3QgdG8uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldEdyb3VwQ2hhbm5lbDogZnVuY3Rpb24gKGdyb3VwTmFtZSkge1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScpO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2dyb3VwJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lXS5qb2luKCcvJyk7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICogICAgICAgICBydW46IHsgbW9kZWw6ICdtb2RlbC5lcW4nIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICogICAgIHdvcmxkTWFuYWdlci5nZXRDdXJyZW50V29ybGQoKS50aGVuKGZ1bmN0aW9uICh3b3JsZE9iamVjdCwgd29ybGRBZGFwdGVyKSB7XG4gICAgICogICAgICAgICB2YXIgd29ybGRDaGFubmVsID0gY20uZ2V0V29ybGRDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHdvcmxkQ2hhbm5lbC5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICogICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICogICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFRoZSB3b3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFdvcmxkQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCBncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHdvcmxkaWQgPSAoJC5pc1BsYWluT2JqZWN0KHdvcmxkKSAmJiB3b3JsZC5pZCkgPyB3b3JsZC5pZCA6IHdvcmxkO1xuICAgICAgICBpZiAoIXdvcmxkaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgYSB3b3JsZCBpZCcpO1xuICAgICAgICB9XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJyk7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvd29ybGQnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgY3VycmVudCBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaW4gdGhhdCB1c2VyJ3MgY3VycmVudCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS4gTm90ZSB0aGF0IHRoaXMgY2hhbm5lbCBvbmx5IGdldHMgbm90aWZpY2F0aW9ucyBmb3Igd29ybGRzIGN1cnJlbnRseSBpbiBtZW1vcnkuIChTZWUgbW9yZSBiYWNrZ3JvdW5kIG9uIFtwZXJzaXN0ZW5jZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlKS4pXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB1c2VyQ2hhbm5lbCA9IGNtLmdldFVzZXJDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHVzZXJDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFVzZXJDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXIsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVzZXJpZCA9ICgkLmlzUGxhaW5PYmplY3QodXNlcikgJiYgdXNlci5pZCkgPyB1c2VyLmlkIDogdXNlcjtcbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkLCB1c2VyaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIHRoYXQgYXV0b21hdGljYWxseSB0cmFja3MgdGhlIHByZXNlbmNlIG9mIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhhdCBpcywgd2hldGhlciB0aGUgZW5kIHVzZXIgaXMgY3VycmVudGx5IG9ubGluZSBpbiB0aGlzIGdyb3VwIGFuZCB3b3JsZC4gTm90aWZpY2F0aW9ucyBhcmUgYXV0b21hdGljYWxseSBzZW50IHdoZW4gdGhlIGVuZCB1c2VyIGNvbWVzIG9ubGluZSwgYW5kIHdoZW4gdGhlIGVuZCB1c2VyIGdvZXMgb2ZmbGluZSAobm90IHByZXNlbnQgZm9yIG1vcmUgdGhhbiAyIG1pbnV0ZXMpLiBVc2VmdWwgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZm9yIGxldHRpbmcgZWFjaCBlbmQgdXNlciBrbm93IHdoZXRoZXIgb3RoZXIgdXNlcnMgaW4gdGhlaXIgc2hhcmVkIHdvcmxkIGFyZSBhbHNvIG9ubGluZS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIG1vZGVsOiAnbW9kZWwuZXFuJ1xuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZFNlcnZpY2UpIHtcbiAgICAgKiAgICAgICAgIHZhciBwcmVzZW5jZUNoYW5uZWwgPSBjbS5nZXRQcmVzZW5jZUNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgcHJlc2VuY2VDaGFubmVsLm9uKCdwcmVzZW5jZScsIGZ1bmN0aW9uIChldnQsIG5vdGlmaWNhdGlvbikge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZyhub3RpZmljYXRpb24ub25saW5lLCBub3RpZmljYXRpb24udXNlcklkKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB3b3JsZGAgV29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB1c2VyaWRgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFByZXNlbmNlQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCB1c2VyaWQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgdmFyIGxhc3RQaW5nVGltZSA9IHsgfTtcblxuICAgICAgICB2YXIgUElOR19JTlRFUlZBTCA9IDYwMDA7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCdpbnRlcm5hbC1waW5nLWNoYW5uZWwnLCBmdW5jdGlvbiAobm90aWZpY2F0aW9uKSB7XG4gICAgICAgICAgICB2YXIgaW5jb21pbmdVc2VySWQgPSBub3RpZmljYXRpb24uZGF0YS51c2VyO1xuICAgICAgICAgICAgaWYgKCFsYXN0UGluZ1RpbWVbaW5jb21pbmdVc2VySWRdICYmIGluY29taW5nVXNlcklkICE9PSB1c2VyaWQpIHtcbiAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDogaW5jb21pbmdVc2VySWQsIG9ubGluZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIHsgdXNlcjogdXNlcmlkIH0pO1xuXG4gICAgICAgICAgICAkLmVhY2gobGFzdFBpbmdUaW1lLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBub3cgPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSAmJiB2YWx1ZSArIChQSU5HX0lOVEVSVkFMICogMikgPCBub3cpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2tleV0gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDoga2V5LCBvbmxpbmU6IGZhbHNlIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBQSU5HX0lOVEVSVkFMKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIGNvbGxlY3Rpb24uIChUaGUgY29sbGVjdGlvbiBuYW1lIGlzIHNwZWNpZmllZCBpbiB0aGUgYHJvb3RgIGFyZ3VtZW50IHdoZW4gdGhlIFtEYXRhIFNlcnZpY2VdKC4uL2RhdGEtYXBpLXNlcnZpY2UvKSBpcyBpbnN0YW50aWF0ZWQuKSBNdXN0IGJlIG9uZSBvZiB0aGUgY29sbGVjdGlvbnMgaW4gdGhpcyBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBhdXRvbWF0aWMgbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWwgd2hlbiBkYXRhIGlzIGNyZWF0ZWQsIHVwZGF0ZWQsIG9yIGRlbGV0ZWQgaW4gdGhpcyBjb2xsZWN0aW9uLiBTZWUgbW9yZSBvbiBbYXV0b21hdGljIG1lc3NhZ2VzIHRvIHRoZSBkYXRhIGNoYW5uZWxdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNkYXRhLW1lc3NhZ2VzKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZ2MgPSBjbS5nZXREYXRhQ2hhbm5lbCgnc3VydmV5LXJlc3BvbnNlcycpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEsIG1ldGEpIHtcbiAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIG1ldGEuZGF0ZSBpcyB0aW1lIG9mIGNoYW5nZSxcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnN1YlR5cGUgaXMgdGhlIGtpbmQgb2YgY2hhbmdlOiBuZXcsIHVwZGF0ZSwgb3IgZGVsZXRlXG4gICAgICogICAgICAgICAgLy8gbWV0YS5wYXRoIGlzIHRoZSBmdWxsIHBhdGggdG8gdGhlIGNoYW5nZWQgZGF0YVxuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKG1ldGEpO1xuICAgICAqICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgY29sbGVjdGlvbmAgTmFtZSBvZiBjb2xsZWN0aW9uIHdob3NlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIHlvdSB3YW50IHRvIHJlY2VpdmUuXG4gICAgICovXG4gICAgZ2V0RGF0YUNoYW5uZWw6IGZ1bmN0aW9uIChjb2xsZWN0aW9uKSB7XG4gICAgICAgIGlmICghY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIGNvbGxlY3Rpb24gdG8gbGlzdGVuIG9uLicpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2RhdGEnLCBhY2NvdW50LCBwcm9qZWN0LCBjb2xsZWN0aW9uXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgLy9UT0RPOiBGaXggYWZ0ZXIgRXBpY2VudGVyIGJ1ZyBpcyByZXNvbHZlZFxuICAgICAgICB2YXIgb2xkc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjYWxsYmFja1dpdGhDbGVhbkRhdGEgPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgICAgICAgICAgICAgIHZhciBtZXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYXlsb2FkLmNoYW5uZWwsXG4gICAgICAgICAgICAgICAgICAgIHN1YlR5cGU6IHBheWxvYWQuZGF0YS5zdWJUeXBlLFxuICAgICAgICAgICAgICAgICAgICBkYXRlOiBwYXlsb2FkLmRhdGEuZGF0ZVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGFjdHVhbERhdGEgPSBwYXlsb2FkLmRhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICBpZiAoYWN0dWFsRGF0YS5kYXRhKSB7IC8vRGVsZXRlIG5vdGlmaWNhdGlvbnMgYXJlIG9uZSBkYXRhLWxldmVsIGJlaGluZCBvZiBjb3Vyc2VcbiAgICAgICAgICAgICAgICAgICAgYWN0dWFsRGF0YSA9IGFjdHVhbERhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIGFjdHVhbERhdGEsIG1ldGEpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aENsZWFuRGF0YSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVQSV9DT09LSUVfS0VZOiAnZXBpY2VudGVyLnByb2plY3QudG9rZW4nLFxuICAgIEVQSV9TRVNTSU9OX0tFWTogJ2VwaWNlbnRlci51c2VyLnNlc3Npb24nLFxuICAgIFNUUkFURUdZX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLXNjZW5hcmlvJ1xufTsiLCIvKipcbiogIyMgUnVuIE1hbmFnZXJcbipcbiogVGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBhY2Nlc3MgdG8gcnVucyBmb3IgeW91ciBwcm9qZWN0LiBUaGlzIGFsbG93cyB5b3UgdG8gcmVhZCBhbmQgdXBkYXRlIHZhcmlhYmxlcywgY2FsbCBvcGVyYXRpb25zLCBldGMuIEFkZGl0aW9uYWxseSwgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLiBTcGVjaWZpY2FsbHksIHlvdSBjYW4gc2VsZWN0IFtydW4gY3JlYXRpb24gc3RyYXRlZ2llcyAocnVsZXMpXSguLi8uLi9zdHJhdGVneS8pIGZvciB3aGljaCBydW5zIGVuZCB1c2VycyBvZiB5b3VyIHByb2plY3Qgd29yayB3aXRoIHdoZW4gdGhleSBsb2cgaW4gdG8geW91ciBwcm9qZWN0LlxuKlxuKiBUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGNyZWF0ZSBuZXcgcnVucywgaW5jbHVkaW5nIHRoZSBFcGljZW50ZXIuanMgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSwgdGhlIFJFU0ZUZnVsIFtSdW4gQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkpIGFuZCB0aGUgW01vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLykuIEhvd2V2ZXIsIGZvciBzb21lIHByb2plY3RzIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gcGljayB1cCB3aGVyZSB0aGUgdXNlciBsZWZ0IG9mZiwgdXNpbmcgYW4gZXhpc3RpbmcgcnVuLiBBbmQgaW4gc29tZSBwcm9qZWN0cywgd2hldGhlciB0byBjcmVhdGUgYSBuZXcgcnVuIG9yIHVzZSBhbiBleGlzdGluZyBvbmUgaXMgY29uZGl0aW9uYWwsIGZvciBleGFtcGxlIGJhc2VkIG9uIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZXhpc3RpbmcgcnVuIG9yIHlvdXIgb3duIGtub3dsZWRnZSBhYm91dCB0aGUgbW9kZWwuIFRoZSBSdW4gTWFuYWdlciBwcm92aWRlcyB0aGlzIGxldmVsIG9mIGNvbnRyb2w6IHlvdXIgY2FsbCB0byBgZ2V0UnVuKClgLCByYXRoZXIgdGhhbiBhbHdheXMgcmV0dXJuaW5nIGEgbmV3IHJ1biwgcmV0dXJucyBhIHJ1biBiYXNlZCBvbiB0aGUgc3RyYXRlZ3kgeW91J3ZlIHNwZWNpZmllZC4gKE5vdGUgdGhhdCBtYW55IG9mIHRoZSBFcGljZW50ZXIgc2FtcGxlIHByb2plY3RzIHVzZSBhIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LCBiZWNhdXNlIGdlbmVyYWxseSB0aGUgc2FtcGxlIHByb2plY3RzIGFyZSBwbGF5ZWQgaW4gb25lIGVuZCB1c2VyIHNlc3Npb24gYW5kIGRvbid0IGNhcmUgYWJvdXQgcnVuIHN0YXRlcyBvciBydW4gc3RyYXRlZ2llcy4pXG4qXG4qXG4qICMjIyBVc2luZyB0aGUgUnVuIE1hbmFnZXIgdG8gY3JlYXRlIGFuZCBhY2Nlc3MgcnVuc1xuKlxuKiBUbyB1c2UgdGhlIFJ1biBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuKlxuKiAgICogYHJ1bmA6IChyZXF1aXJlZCkgUnVuIG9iamVjdC4gTXVzdCBjb250YWluOlxuKiAgICAgICAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICAgICAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4qICAgICAgICogYG1vZGVsYDogVGhlIG5hbWUgb2YgeW91ciBwcmltYXJ5IG1vZGVsIGZpbGUuIChTZWUgbW9yZSBvbiBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4pXG4qICAgICAgICogYHNjb3BlYDogKG9wdGlvbmFsKSBTY29wZSBvYmplY3QgZm9yIHRoZSBydW4sIGZvciBleGFtcGxlIGBzY29wZS5ncm91cGAgd2l0aCB2YWx1ZSBvZiB0aGUgbmFtZSBvZiB0aGUgZ3JvdXAuXG4qICAgICAgICogYHNlcnZlcmA6IChvcHRpb25hbCkgQW4gb2JqZWN0IHdpdGggb25lIGZpZWxkLCBgaG9zdGAuIFRoZSB2YWx1ZSBvZiBgaG9zdGAgaXMgdGhlIHN0cmluZyBgYXBpLmZvcmlvLmNvbWAsIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4qICAgICAgICogYGZpbGVzYDogKG9wdGlvbmFsKSBJZiBhbmQgb25seSBpZiB5b3UgYXJlIHVzaW5nIGEgVmVuc2ltIG1vZGVsIGFuZCB5b3UgaGF2ZSBhZGRpdGlvbmFsIGRhdGEgdG8gcGFzcyBpbiB0byB5b3VyIG1vZGVsLCB5b3UgY2FuIHBhc3MgYSBgZmlsZXNgIG9iamVjdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgZmlsZXMsIGZvciBleGFtcGxlOiBgXCJmaWxlc1wiOiB7XCJkYXRhXCI6IFwibXlFeHRyYURhdGEueGxzXCJ9YC4gKE5vdGUgdGhhdCB5b3UnbGwgYWxzbyBuZWVkIHRvIGFkZCB0aGlzIHNhbWUgZmlsZXMgb2JqZWN0IHRvIHlvdXIgVmVuc2ltIFtjb25maWd1cmF0aW9uIGZpbGVdKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltLykuKSBTZWUgdGhlIFt1bmRlcmx5aW5nIE1vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLyNwb3N0LWNyZWF0aW5nLWEtbmV3LXJ1bi1mb3ItdGhpcy1wcm9qZWN0KSBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbi5cbipcbiogICAqIGBzdHJhdGVneWA6IChvcHRpb25hbCkgUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4qXG4qICAgKiBgc2Vzc2lvbktleWA6IChvcHRpb25hbCkgTmFtZSBvZiBicm93c2VyIGNvb2tpZSBpbiB3aGljaCB0byBzdG9yZSBydW4gaW5mb3JtYXRpb24sIGluY2x1ZGluZyBydW4gaWQuIE1hbnkgY29uZGl0aW9uYWwgc3RyYXRlZ2llcywgaW5jbHVkaW5nIHRoZSBwcm92aWRlZCBzdHJhdGVnaWVzLCByZWx5IG9uIHRoaXMgYnJvd3NlciBjb29raWUgdG8gc3RvcmUgdGhlIHJ1biBpZCBhbmQgaGVscCBtYWtlIHRoZSBkZWNpc2lvbiBvZiB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZS4gVGhlIG5hbWUgb2YgdGhpcyBjb29raWUgZGVmYXVsdHMgdG8gYGVwaWNlbnRlci1zY2VuYXJpb2AgYW5kIGNhbiBiZSBzZXQgd2l0aCB0aGUgYHNlc3Npb25LZXlgIHBhcmFtZXRlci5cbipcbipcbiogQWZ0ZXIgaW5zdGFudGlhdGluZyBhIFJ1biBNYW5hZ2VyLCBtYWtlIGEgY2FsbCB0byBgZ2V0UnVuKClgIHdoZW5ldmVyIHlvdSBuZWVkIHRvIGFjY2VzcyBhIHJ1biBmb3IgdGhpcyBlbmQgdXNlci4gVGhlIGBSdW5NYW5hZ2VyLnJ1bmAgY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLiBUaGUgUnVuIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBhY2Nlc3MgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy5cbipcbiogKipFeGFtcGxlKipcbipcbiogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiogICAgICAgICAgIHJ1bjoge1xuKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJyxcbiogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiogICAgICAgICAgIH0sXG4qICAgICAgICAgICBzdHJhdGVneTogJ2Fsd2F5cy1uZXcnLFxuKiAgICAgICAgICAgc2Vzc2lvbktleTogJ2VwaWNlbnRlci1zZXNzaW9uJ1xuKiAgICAgICB9KTtcbiogICAgICAgcm0uZ2V0UnVuKClcbiogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuKiAgICAgICAgICAgICAgIC8vIHRoZSByZXR1cm4gdmFsdWUgb2YgZ2V0UnVuKCkgaXMgYSBydW4gb2JqZWN0XG4qICAgICAgICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gYWxzbyBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuKiAgICAgICAgICAgICAgIC8vIHNvIGFueSBSdW4gU2VydmljZSBtZXRob2QgaXMgdmFsaWQgaGVyZVxuKiAgICAgICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiogICAgICAgfSlcbipcbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBzdHJhdGVnaWVzTWFwID0gcmVxdWlyZSgnLi9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcCcpO1xudmFyIHNwZWNpYWxPcGVyYXRpb25zID0gcmVxdWlyZSgnLi9zcGVjaWFsLW9wZXJhdGlvbnMnKTtcbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcblxuXG5mdW5jdGlvbiBwYXRjaFJ1blNlcnZpY2Uoc2VydmljZSwgbWFuYWdlcikge1xuICAgIGlmIChzZXJ2aWNlLnBhdGNoZWQpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuXG4gICAgdmFyIG9yaWcgPSBzZXJ2aWNlLmRvO1xuICAgIHNlcnZpY2UuZG8gPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHJlc2VydmVkT3BzID0gT2JqZWN0LmtleXMoc3BlY2lhbE9wZXJhdGlvbnMpO1xuICAgICAgICBpZiAocmVzZXJ2ZWRPcHMuaW5kZXhPZihvcGVyYXRpb24pID09PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG9yaWcuYXBwbHkoc2VydmljZSwgYXJndW1lbnRzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT3BlcmF0aW9uc1tvcGVyYXRpb25dLmNhbGwoc2VydmljZSwgcGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBzZXJ2aWNlLnBhdGNoZWQgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHNlcnZpY2U7XG59XG5cblxuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cblxuICAgIHN0cmF0ZWd5OiAnbmV3LWlmLWluaXRpYWxpemVkJ1xufTtcblxuZnVuY3Rpb24gUnVuTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMucnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICB0aGlzLnJ1biA9IHRoaXMub3B0aW9ucy5ydW47XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5ydW4gPSBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMucnVuKTtcbiAgICB9XG5cbiAgICBwYXRjaFJ1blNlcnZpY2UodGhpcy5ydW4sIHRoaXMpO1xuXG4gICAgdmFyIFN0cmF0ZWd5Q3RvciA9IHR5cGVvZiB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgPT09ICdmdW5jdGlvbicgPyB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgOiBzdHJhdGVnaWVzTWFwW3RoaXMub3B0aW9ucy5zdHJhdGVneV07XG5cbiAgICBpZiAoIVN0cmF0ZWd5Q3Rvcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NwZWNpZmllZCBydW4gY3JlYXRpb24gc3RyYXRlZ3kgd2FzIGludmFsaWQ6JywgdGhpcy5vcHRpb25zLnN0cmF0ZWd5KTtcbiAgICB9XG5cbiAgICB0aGlzLnN0cmF0ZWd5ID0gbmV3IFN0cmF0ZWd5Q3Rvcih0aGlzLnJ1biwgdGhpcy5vcHRpb25zKTtcbn1cblxuUnVuTWFuYWdlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSAnZ29vZCcgcnVuLlxuICAgICAqXG4gICAgICogQSBnb29kIHJ1biBpcyBkZWZpbmVkIGJ5IHRoZSBzdHJhdGVneS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBzdHJhdGVneSBpcyBgYWx3YXlzLW5ld2AsIHRoZSBjYWxsXG4gICAgICogdG8gYGdldFJ1bigpYCBhbHdheXMgcmV0dXJucyBhIG5ld2x5IGNyZWF0ZWQgcnVuOyBpZiB0aGUgc3RyYXRlZ3kgaXMgYG5ldy1pZi1wZXJzaXN0ZWRgLFxuICAgICAqIGBnZXRSdW4oKWAgY3JlYXRlcyBhIG5ldyBydW4gaWYgdGhlIHByZXZpb3VzIHJ1biBpcyBpbiBhIHBlcnNpc3RlZCBzdGF0ZSwgb3RoZXJ3aXNlXG4gICAgICogaXQgcmV0dXJucyB0aGUgcHJldmlvdXMgcnVuLiBTZWUgW1J1biBNYW5hZ2VyIFN0cmF0ZWdpZXNdKC4uLy4uL3N0cmF0ZWd5LykgZm9yIG1vcmUgb24gc3RyYXRlZ2llcy5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5nZXRSdW4oKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqIEByZXR1cm4geyRwcm9taXNlfSBQcm9taXNlIHRvIGNvbXBsZXRlIHRoZSBjYWxsLlxuICAgICAqL1xuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdHJhdGVneVxuICAgICAgICAgICAgICAgIC5nZXRSdW4oKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSBuZXcgcnVuLCByZWdhcmRsZXNzIG9mIHN0cmF0ZWd5OiBmb3JjZSBjcmVhdGlvbiBvZiBhIG5ldyBydW4uXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgcm0ucmVzZXQoKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIChuZXcpIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBydW5TZXJ2aWNlT3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgUnVuIFNlcnZpY2UuIFNlZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBmb3IgbW9yZS5cbiAgICAgKi9cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5LnJlc2V0KHJ1blNlcnZpY2VPcHRpb25zKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJ1bk1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIC8vIGFsd2F5cyBjcmVhdGUgYSBuZXcgcnVuIVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1ha2VTZXEgPSByZXF1aXJlKCcuLi8uLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFNlc3Npb25TdG9yZSA9IHJlcXVpcmUoJy4uLy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBVcmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgc2Vzc2lvblN0b3JlID0gbmV3IFNlc3Npb25TdG9yZSh7fSk7XG52YXIgdXJsU2VydmljZSA9IG5ldyBVcmxTZXJ2aWNlKCk7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9rZXktbmFtZXMnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHNlc3Npb25LZXk6IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZLFxuICAgIHBhdGg6ICcnXG59O1xuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBwYXRoKSB7XG4gICAgaWYgKCFwYXRoKSB7XG4gICAgICAgIGlmICghdXJsU2VydmljZS5pc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgICAgICBwYXRoID0gJy8nICsgW3VybFNlcnZpY2UuYXBwUGF0aCwgdXJsU2VydmljZS5hY2NvdW50UGF0aCwgdXJsU2VydmljZS5wcm9qZWN0UGF0aF0uam9pbignLycpO1xuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHdlIGRvbid0IGdldCBjb25zZWN1dGVpdmUgJy8nIHNvIHdlIGhhdmUgYSB2YWxpZCBwYXRoIGZvciB0aGUgc2Vzc2lvblxuICAgICAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZSgvXFwvezIsfS9nLCcvJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYXRoID0gJyc7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gc2V0IHRoZSBzZWVzaW9uS2V5IGZvciB0aGUgcnVuXG4gICAgc2Vzc2lvblN0b3JlLnNldChzZXNzaW9uS2V5LCBKU09OLnN0cmluZ2lmeSh7IHJ1bklkOiBydW4uaWQgfSksIHsgcm9vdDogcGF0aCB9KTtcbn1cblxuLyoqXG4qIENvbmRpdGlvbmFsIENyZWF0aW9uIFN0cmF0ZWd5XG4qIFRoaXMgc3RyYXRlZ3kgd2lsbCB0cnkgdG8gZ2V0IHRoZSBydW4gc3RvcmVkIGluIHRoZSBjb29raWUgYW5kXG4qIGV2YWx1YXRlIGlmIG5lZWRzIHRvIGNyZWF0ZSBhIG5ldyBydW4gYnkgY2FsbGluZyB0aGUgJ2NvbmRpdGlvbicgZnVuY3Rpb25cbiovXG5cbi8qIGpzaGludCBlcW51bGw6IHRydWUgKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KHJ1blNlcnZpY2UsIGNvbmRpdGlvbiwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChjb25kaXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb25kaXRpb25hbCBzdHJhdGVneSBuZWVkcyBhIGNvbmRpdGlvbiB0byBjcmVhdGV0ZSBhIHJ1bicpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fYXV0aCA9IG5ldyBBdXRoTWFuYWdlcigpO1xuICAgICAgICB0aGlzLnJ1biA9IG1ha2VTZXEocnVuU2VydmljZSk7XG4gICAgICAgIHRoaXMuY29uZGl0aW9uID0gdHlwZW9mIGNvbmRpdGlvbiAhPT0gJ2Z1bmN0aW9uJyA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNvbmRpdGlvbjsgfSA6IGNvbmRpdGlvbjtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9LFxuXG4gICAgcnVuT3B0aW9uc1dpdGhTY29wZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdXNlclNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiB1c2VyU2Vzc2lvbi5ncm91cE5hbWUgfVxuICAgICAgICB9LCB0aGlzLnJ1bk9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBvcHQgPSB0aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5ydW5cbiAgICAgICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgc2V0UnVuSW5TZXNzaW9uKF90aGlzLm9wdGlvbnMuc2Vzc2lvbktleSwgcnVuLCBfdGhpcy5vcHRpb25zLnBhdGgpO1xuICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmUuZ2V0KHRoaXMub3B0aW9ucy5zZXNzaW9uS2V5KSk7XG5cbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRBbmRDaGVjayhydW5TZXNzaW9uKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgX2xvYWRBbmRDaGVjazogZnVuY3Rpb24gKHJ1blNlc3Npb24pIHtcbiAgICAgICAgdmFyIHNob3VsZENyZWF0ZSA9IGZhbHNlO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1blxuICAgICAgICAgICAgLmxvYWQocnVuU2Vzc2lvbi5ydW5JZCwgbnVsbCwge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uIChydW4sIG1zZywgaGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBzaG91bGRDcmVhdGUgPSBfdGhpcy5jb25kaXRpb24uY2FsbChfdGhpcywgcnVuLCBoZWFkZXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIGlmIChzaG91bGRDcmVhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9wdCA9IF90aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgbmVlZCB0byBkbyB0aGlzLCBvbiB0aGUgb3JpZ2luYWwgcnVuU2VydmljZSAoaWUgbm90IHNlcXVlbmNpYWxpemVkKVxuICAgICAgICAgICAgICAgICAgICAvLyBzbyB3ZSBkb24ndCBnZXQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1bi5vcmlnaW5hbC5jcmVhdGUob3B0KVxuICAgICAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oX3RoaXMub3B0aW9ucy5zZXNzaW9uS2V5LCBydW4pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnN0YXJ0KCk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSAgPSBydW5TZXJ2aWNlO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSBuZXdseSBjcmVhdGVkIHJ1blxuICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoKS5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSh0aGlzLnJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vaWRlbnRpdHktc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0b3JlOiB7XG4gICAgICAgIHN5bmNocm9ub3VzOiB0cnVlXG4gICAgfVxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcblxuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMud29ybGRBcGkgPSBuZXcgV29ybGRBcGlBZGFwdGVyKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciB3b3JsZEFwaSA9IHRoaXMud29ybGRBcGk7XG4gICAgICAgIHZhciBtb2RlbCA9IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAoIWN1clVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDAsIGVycm9yOiAnV2UgbmVlZCBhbiBhdXRoZW50aWNhdGVkIHVzZXIgdG8gam9pbiBhIG11bHRpcGxheWVyIHdvcmxkLiAoRVJSOiBubyB1c2VySWQgaW4gc2Vzc2lvbiknIH0sIHNlc3Npb24pLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsb2FkUnVuRnJvbVdvcmxkID0gZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDQsIGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IGluIGFueSB3b3JsZC4nIH0sIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oX3RoaXMuX2xvYWRSdW4pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgZHRkLnJlamVjdChlcnJvciwgc2Vzc2lvbiwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIF9sb2FkUnVuOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIFN0YXRlQXBpID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICAgICAgdGhpcy5fc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICAgICAgdGhpcy5zdGF0ZUFwaSA9IG5ldyBTdGF0ZUFwaSgpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZEFuZENoZWNrID0gdGhpcy5fbG9hZEFuZENoZWNrLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVSdW4gPSB0aGlzLl9yZXN0b3JlUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2dldEFsbFJ1bnMgPSB0aGlzLl9nZXRBbGxSdW5zLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0QWxsUnVucygpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9sb2FkQW5kQ2hlY2spO1xuICAgIH0sXG5cbiAgICBfZ2V0QWxsUnVuczogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2UodGhpcy5fc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9Jyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5xdWVyeSh7XG4gICAgICAgICAgICAndXNlci5pZCc6IHNlc3Npb24udXNlcklkIHx8ICcwMDAwJyxcbiAgICAgICAgICAgICdzY29wZS5ncm91cCc6IHNlc3Npb24uZ3JvdXBOYW1lXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVucykge1xuICAgICAgICBpZiAoIXJ1bnMgfHwgIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGVDb21wID0gZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIuZGF0ZSkgLSBuZXcgRGF0ZShhLmRhdGUpOyB9O1xuICAgICAgICB2YXIgbGF0ZXN0UnVuID0gcnVucy5zb3J0KGRhdGVDb21wKVswXTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHNob3VsZFJlcGxheSA9IGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGxhdGVzdFJ1bi5pZCwgbnVsbCwge1xuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVwbGF5ID0gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2hvdWxkUmVwbGF5ID8gX3RoaXMuX3Jlc3RvcmVSdW4ocnVuLmlkKSA6IHJ1bjtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9yZXN0b3JlUnVuOiBmdW5jdGlvbiAocnVuSWQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVBcGkucmVwbGF5KHsgcnVuSWQ6IHJ1bklkIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJ1bihyZXNwLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW4ubG9hZChpZCwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgICduZXctaWYtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLFxuICAgICduZXctaWYtcGVyc2lzdGVkJzogcmVxdWlyZSgnLi9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1taXNzaW5nJzogcmVxdWlyZSgnLi9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpLFxuICAgICdhbHdheXMtbmV3JzogcmVxdWlyZSgnLi9hbHdheXMtbmV3LXN0cmF0ZWd5JyksXG4gICAgJ211bHRpcGxheWVyJzogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdwZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXInOiByZXF1aXJlKCcuL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneScpLFxuICAgICdub25lJzogcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgdmFsaWRGaWx0ZXI6IHsgc2F2ZWQ6IHRydWUgfVxufTtcblxuZnVuY3Rpb24gU2NlbmFyaW9NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMucnVuU2VydmljZSA9IHRoaXMub3B0aW9ucy5ydW4gfHwgbmV3IFJ1blNlcnZpY2UodGhpcy5vcHRpb25zKTtcbn1cblxuU2NlbmFyaW9NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy52YWxpZEZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlcik7XG4gICAgfSxcblxuICAgIGxvYWRWYXJpYWJsZXM6IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UucXVlcnkodGhpcy5maWx0ZXIsIHsgaW5jbHVkZTogdmFycyB9KTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgbWV0YSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2VydmljZShydW4pLnNhdmUoJC5leHRlbmQodHJ1ZSwge30sIHsgc2F2ZWQ6IHRydWUgfSwgbWV0YSkpO1xuICAgIH0sXG5cbiAgICBhcmNoaXZlOiBmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSh7IHNhdmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuXG4gICAgX2dldFNlcnZpY2U6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW4gfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdvYmplY3QnICYmIHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NhdmUgbWV0aG9kIHJlcXVpcmVzIGEgcnVuIHNlcnZpY2Ugb3IgYSBydW5JZCcpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW5JZCB9KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICByZXNldDogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucywgbWFuYWdlcikge1xuICAgICAgICByZXR1cm4gbWFuYWdlci5yZXNldChvcHRpb25zKTtcbiAgICB9XG59O1xuIiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9ICByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG4vLyB2YXIgZGVmYXVsdHMgPSB7XG4vLyAgYWNjb3VudDogJycsXG4vLyAgcHJvamVjdDogJycsXG4vLyAgZ3JvdXA6ICcnLFxuLy8gIHRyYW5zcG9ydDoge1xuLy8gIH1cbi8vIH07XG5cblxuZnVuY3Rpb24gYnVpbGRTdHJhdGVneSh3b3JsZElkLCBkdGQpIHtcblxuICAgIHJldHVybiBmdW5jdGlvbiBDdG9yKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICAkLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm90IGltcGxlbWVudGQuIE5lZWQgYXBpIGNoYW5nZXMnKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlLmNhbGwodGhpcywgcnVuLCBfdGhpcy5ydW5TZXJ2aWNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcklkYCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSBncm91cCBmb3IgdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bih7bW9kZWw6ICdteU1vZGVsLnB5J30pXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBtb2RlbGAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgbW9kZWwgZmlsZS4gUmVxdWlyZWQgaWYgbm90IGFscmVhZHkgcGFzc2VkIGluIGFzIGBydW4ubW9kZWxgIHdoZW4gdGhlIFdvcmxkIE1hbmFnZXIgaXMgY3JlYXRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgX3RoaXMub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJtLmdldFJ1bigpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHJ1biwgcm0ucnVuU2VydmljZSwgcm0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5nZXRDdXJyZW50V29ybGQoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bik7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIGFwaSk7XG59O1xuIiwiLyoqXG4gKiAjI0ZpbGUgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGlzIGlzIHVzZWQgdG8gdXBsb2FkL2Rvd25sb2FkIGZpbGVzIGRpcmVjdGx5IG9udG8gRXBpY2VudGVyLCBhbmFsb2dvdXMgdG8gdXNpbmcgdGhlIEZpbGUgTWFuYWdlciBVSSBpbiBFcGljZW50ZXIgZGlyZWN0bHkgb3IgU0ZUUGluZyBmaWxlcyBpbi4gVGhlIEFzc2V0IEFQSSBpcyB0eXBpY2FsbHkgdXNlZCBmb3IgYWxsIHByb2plY3QgdXNlLWNhc2VzLCBhbmQgaXQncyB1bmxpa2VseSB0aGlzIEZpbGUgU2VydmljZSB3aWxsIGJlIHVzZWQgZGlyZWN0bHkgZXhjZXB0IGJ5IEFkbWluIHRvb2xzIChlLmcuIEZsb3cgSW5zcGVjdG9yKS5cbiAqXG4gKiBQYXJ0aWFsbHkgaW1wbGVtZW50ZWQuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCBzdG9yZS5nZXQoJ2VwaWNlbnRlci50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZmlsZScpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQXN5bmNBUEkgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgYSBkaXJlY3RvcnkgbGlzdGluZywgb3IgY29udGVudHMgb2YgYSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGZpbGVQYXRoYCAgIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZm9sZGVyVHlwZWAgT25lIG9mIE1vZGVsfFN0YXRpY3xOb2RlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBnZXRDb250ZW50czogZnVuY3Rpb24gKGZpbGVQYXRoLCBmb2xkZXJUeXBlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IGZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbi8vIHZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGtleU5hbWVzID0gcmVxdWlyZSgnLi4vbWFuYWdlcnMva2V5LW5hbWVzJyk7XG5cbnZhciBhcGlFbmRwb2ludCA9ICdhc3NldCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZShzdG9yZS5nZXQoa2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZKSB8fCAne30nKTtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9DT09LSUVfS0VZKSB8fCAnJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gRGVmYXVsdHMgdG8gc2Vzc2lvbidzIGBncm91cE5hbWVgLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogc2Vzc2lvbi51c2VySWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgc2NvcGUgZm9yIHRoZSBhc3NldC4gVmFsaWQgdmFsdWVzIGFyZTogYHVzZXJgLCBgZ3JvdXBgLCBhbmQgYHByb2plY3RgLiBTZWUgYWJvdmUgZm9yIHRoZSByZXF1aXJlZCBwZXJtaXNzaW9ucyB0byB3cml0ZSB0byBlYWNoIHNjb3BlLiBEZWZhdWx0cyB0byBgdXNlcmAsIG1lYW5pbmcgdGhlIGN1cnJlbnQgZW5kIHVzZXIgb3IgYSBmYWNpbGl0YXRvciBpbiB0aGUgZW5kIHVzZXIncyBncm91cCBjYW4gZWRpdCB0aGUgYXNzZXQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBzY29wZTogJ3VzZXInLFxuICAgICAgICAvKipcbiAgICAgICAgICogRGV0ZXJtaW5lcyBpZiBhIHJlcXVlc3QgdG8gbGlzdCB0aGUgYXNzZXRzIGluIGEgc2NvcGUgaW5jbHVkZXMgdGhlIGNvbXBsZXRlIFVSTCBmb3IgZWFjaCBhc3NldCAoYHRydWVgKSwgb3Igb25seSB0aGUgZmlsZSBuYW1lcyBvZiB0aGUgYXNzZXRzIChgZmFsc2VgKS4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGZ1bGxVcmw6IHRydWUsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgdHJhbnNwb3J0IG9iamVjdCBjb250YWlucyB0aGUgb3B0aW9ucyBwYXNzZWQgdG8gdGhlIFhIUiByZXF1ZXN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7XG4gICAgICAgICAgICBwcm9jZXNzRGF0YTogZmFsc2VcbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIGFzc2V0QXBpUGFyYW1zID0gWydlbmNvZGluZycsICdkYXRhJywgJ2NvbnRlbnRUeXBlJ107XG4gICAgdmFyIHNjb3BlQ29uZmlnID0ge1xuICAgICAgICB1c2VyOiBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSxcbiAgICAgICAgZ3JvdXA6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10sXG4gICAgICAgIHByb2plY3Q6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0J10sXG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZUZpbGVuYW1lID0gZnVuY3Rpb24gKGZpbGVuYW1lKSB7XG4gICAgICAgIGlmICghZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZmlsZW5hbWUgaXMgbmVlZGVkLicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZVVybFBhcmFtcyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICBpZiAoIXBhcnRLZXlzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Njb3BlIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cblxuICAgICAgICAkLmVhY2gocGFydEtleXMsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICghb3B0aW9uc1t0aGlzXSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzICsgJyBwYXJhbWV0ZXIgaXMgbmVlZGVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgdmFyIGJ1aWxkVXJsID0gZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgIHZhbGlkYXRlVXJsUGFyYW1zKG9wdGlvbnMpO1xuICAgICAgICB2YXIgcGFydEtleXMgPSBzY29wZUNvbmZpZ1tvcHRpb25zLnNjb3BlXTtcbiAgICAgICAgdmFyIHBhcnRzID0gJC5tYXAocGFydEtleXMsIGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zW2tleV07XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgcHJldmVudHMgYWRkaW5nIGEgdHJhaWxpbmcgLyBpbiB0aGUgVVJMIGFzIHRoZSBBc3NldCBBUElcbiAgICAgICAgICAgIC8vIGRvZXMgbm90IHdvcmsgY29ycmVjdGx5IHdpdGggaXRcbiAgICAgICAgICAgIGZpbGVuYW1lID0gJy8nICsgZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHBhcnRzLmpvaW4oJy8nKSArIGZpbGVuYW1lO1xuICAgIH07XG5cbiAgICAvLyBQcml2YXRlIGZ1bmN0aW9uLCBhbGwgcmVxdWVzdHMgZm9sbG93IGEgbW9yZSBvciBsZXNzIHNhbWUgYXBwcm9hY2ggdG9cbiAgICAvLyB1c2UgdGhlIEFzc2V0IEFQSSBhbmQgdGhlIGRpZmZlcmVuY2UgaXMgdGhlIEhUVFAgdmVyYlxuICAgIC8vXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBtZXRob2RgIChSZXF1aXJlZCkgSFRUUCB2ZXJiXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS9yZXBsYWNlL2NyZWF0ZVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUElcbiAgICAvLyBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgdmFyIHVwbG9hZCA9IGZ1bmN0aW9uIChtZXRob2QsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVGaWxlbmFtZShmaWxlbmFtZSk7XG4gICAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgcGFyYW1ldGVyIGlzIGNsZWFuXG4gICAgICAgIG1ldGhvZCA9IG1ldGhvZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB2YXIgY29udGVudFR5cGUgPSBwYXJhbXMgaW5zdGFuY2VvZiBGb3JtRGF0YSA9PT0gdHJ1ZSA/IGZhbHNlIDogJ2FwcGxpY2F0aW9uL2pzb24nO1xuICAgICAgICBpZiAoY29udGVudFR5cGUgPT09ICdhcHBsaWNhdGlvbi9qc29uJykge1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIGFzc2V0QXBpUGFyYW1zKTtcbiAgICAgICAgfSBlbHNlIHsgLy8gZWxzZSB3ZSdyZSBzZW5kaW5nIGZvcm0gZGF0YSB3aGljaCBnb2VzIGRpcmVjdGx5IGluIHJlcXVlc3QgYm9keVxuICAgICAgICAgICAgLy8gRm9yIG11bHRpcGFydC9mb3JtLWRhdGEgdXBsb2FkcyB0aGUgZmlsZW5hbWUgaXMgbm90IHNldCBpbiB0aGUgVVJMLFxuICAgICAgICAgICAgLy8gaXQncyBnZXR0aW5nIHBpY2tlZCBieSB0aGUgRm9ybURhdGEgZmllbGQgZmlsZW5hbWUuXG4gICAgICAgICAgICBmaWxlbmFtZSA9IG1ldGhvZCA9PT0gJ3Bvc3QnIHx8IG1ldGhvZCA9PT0gJ3B1dCcgPyAnJyA6IGZpbGVuYW1lO1xuICAgICAgICB9XG4gICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCwgY29udGVudFR5cGU6IGNvbnRlbnRUeXBlIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwW21ldGhvZF0ocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS4gVGhlIHNlcnZlciByZXR1cm5zIGFuIGVycm9yIChzdGF0dXMgY29kZSBgNDA5YCwgY29uZmxpY3QpIGlmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLCBzb1xuICAgICAgICAqIGNoZWNrIGZpcnN0IHdpdGggYSBgbGlzdCgpYCBvciBhIGBnZXQoKWAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBhYSA9IG5ldyBGLnNlcnZpY2UuQXNzZXQoe1xuICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAgICAqICAgICAgICAgIHVzZXJJZDogJydcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAgICAgICAgKiAgICAgICBhYS5jcmVhdGUoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gICAgICAgICogICAgICAgICAgIGNvbnRlbnRUeXBlOiAndGV4dC9wbGFpbidcbiAgICAgICAgKiAgICAgICB9LCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyBhbHRlcm5hdGl2ZWx5LCBjcmVhdGUgYSBuZXcgYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJ1cGxvYWQtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5VcGxvYWQgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3VwbG9hZC1maWxlJykub24oJ3N1Ym1pdCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLmNyZWF0ZShmaWxlbmFtZSwgZGF0YSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gY3JlYXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUEkuIFJlcXVpcmVkIGlmIHRoZSBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYCwgb3RoZXJ3aXNlIGlnbm9yZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZW5jb2RpbmdgIEVpdGhlciBgSEVYYCBvciBgQkFTRV82NGAuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmRhdGFgIFRoZSBlbmNvZGVkIGRhdGEgZm9yIHRoZSBmaWxlLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5jb250ZW50VHlwZWAgVGhlIG1pbWUgdHlwZSBvZiB0aGUgZmlsZS4gT3B0aW9uYWwuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3Bvc3QnLCBmaWxlbmFtZSwgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGEgZmlsZSBmcm9tIHRoZSBBc3NldCBBUEksIGZldGNoaW5nIHRoZSBhc3NldCBjb250ZW50LiAoVG8gZ2V0IGEgbGlzdFxuICAgICAgICAqIG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZSwgdXNlIGBsaXN0KClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byByZXRyaWV2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBnZXRTZXJ2aWNlT3B0aW9ucyA9IF9waWNrKHNlcnZpY2VPcHRpb25zLCBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSk7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBnZXRTZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBsaXN0IG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5saXN0KHsgZnVsbFVybDogdHJ1ZSB9KS50aGVuKGZ1bmN0aW9uKGZpbGVMaXN0KXtcbiAgICAgICAgKiAgICAgICAgICAgY29uc29sZS5sb2coJ2FycmF5IG9mIGZpbGVzID0gJywgZmlsZUxpc3QpO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5zY29wZWAgKE9wdGlvbmFsKSBUaGUgc2NvcGUgKGB1c2VyYCwgYGdyb3VwYCwgYHByb2plY3RgKS5cbiAgICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGBvcHRpb25zLmZ1bGxVcmxgIChPcHRpb25hbCkgRGV0ZXJtaW5lcyBpZiB0aGUgbGlzdCBvZiBhc3NldHMgaW4gYSBzY29wZSBpbmNsdWRlcyB0aGUgY29tcGxldGUgVVJMIGZvciBlYWNoIGFzc2V0IChgdHJ1ZWApLCBvciBvbmx5IHRoZSBmaWxlIG5hbWVzIG9mIHRoZSBhc3NldHMgKGBmYWxzZWApLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybCgnJywgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuICAgICAgICAgICAgdmFyIGZ1bGxVcmwgPSBnZXRPcHRpb25zLmZ1bGxVcmw7XG5cbiAgICAgICAgICAgIGlmICghZnVsbFVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZnVsbFBhdGhGaWxlcyA9ICQubWFwKGZpbGVzLCBmdW5jdGlvbiAoZmlsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoZnVsbFBhdGhGaWxlcywgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlcGxhY2VzIGFuIGV4aXN0aW5nIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyByZXBsYWNlIGFuIGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLnJlcGxhY2UoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhObFkyOXVaQ0IwWlhOMElHWnBiR1V1JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJyZXBsYWNlLWZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwicmVwbGFjZS1maWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5SZXBsYWNlIG15RmlsZTwvYnV0dG9uPlxuICAgICAgICAqICAgICAgIC8vIDwvZm9ybT5cbiAgICAgICAgKiAgICAgICAvL1xuICAgICAgICAqICAgICAgICQoJyNyZXBsYWNlLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI3JlcGxhY2UtZmlsZW5hbWUnKS52YWwoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICAgICAgICAqICAgICAgICAgIGRhdGEuYXBwZW5kKCdmaWxlJywgaW5wdXRDb250cm9sLmZpbGVzWzBdLCBmaWxlbmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICBhYS5yZXBsYWNlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgYmVpbmcgcmVwbGFjZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgcmVwbGFjZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3B1dCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5kZWxldGUoc2FtcGxlRmlsZU5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ2RlbGV0ZScsIGZpbGVuYW1lLCB7fSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYXNzZXRVcmw6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlIHByb3ZpZGVzIG1ldGhvZHMgZm9yIGxvZ2dpbmcgaW4gYW5kIGxvZ2dpbmcgb3V0LiBPbiBsb2dpbiwgdGhpcyBzZXJ2aWNlIGNyZWF0ZXMgYW5kIHJldHVybnMgYSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAqXG4gKiBVc2VyIGFjY2VzcyB0b2tlbnMgYXJlIHJlcXVpcmVkIGZvciBlYWNoIGNhbGwgdG8gRXBpY2VudGVyLiAoU2VlIFtQcm9qZWN0IEFjY2Vzc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4pXG4gKlxuICogSWYgeW91IG5lZWQgYWRkaXRpb25hbCBmdW5jdGlvbmFsaXR5IC0tIHN1Y2ggYXMgdHJhY2tpbmcgc2Vzc2lvbiBpbmZvcm1hdGlvbiwgZWFzaWx5IHJldHJpZXZpbmcgdGhlIHVzZXIgdG9rZW4sIG9yIGdldHRpbmcgdGhlIGdyb3VwcyB0byB3aGljaCBhbiBlbmQgdXNlciBiZWxvbmdzIC0tIGNvbnNpZGVyIHVzaW5nIHRoZSBbQXV0aG9yaXphdGlvbiBNYW5hZ2VyXSguLi9hdXRoLW1hbmFnZXIvKSBpbnN0ZWFkLlxuICpcbiAqICAgICAgdmFyIGF1dGggPSBuZXcgRi5zZXJ2aWNlLkF1dGgoKTtcbiAqICAgICAgYXV0aC5sb2dpbih7IHVzZXJOYW1lOiAnanNtaXRoQGFjbWVzaW11bGF0aW9ucy5jb20nLFxuICogICAgICAgICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyB9KTtcbiAqICAgICAgYXV0aC5sb2dvdXQoKTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VyTmFtZTogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFzc3dvcmQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gUmVxdWlyZWQgaWYgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdhdXRoZW50aWNhdGlvbicpXG4gICAgfSk7XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvZ3MgdXNlciBpbiwgcmV0dXJuaW5nIHRoZSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAgICAgICAgICpcbiAgICAgICAgICogSWYgbm8gYHVzZXJOYW1lYCBvciBgcGFzc3dvcmRgIHdlcmUgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLCB0aGV5IGFyZSByZXF1aXJlZCBpbiB0aGUgYG9wdGlvbnNgIGhlcmUuIElmIG5vIGBhY2NvdW50YCB3YXMgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zIGFuZCB0aGUgYHVzZXJOYW1lYCBpcyBmb3IgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGUgYGFjY291bnRgIGlzIHJlcXVpcmVkIGFzIHdlbGwuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgYXV0aC5sb2dpbih7XG4gICAgICAgICAqICAgICAgICAgIHVzZXJOYW1lOiAnanNtaXRoJyxcbiAgICAgICAgICogICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcsXG4gICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyB9KVxuICAgICAgICAgKiAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhcInVzZXIgYWNjZXNzIHRva2VuIGlzOiBcIiwgdG9rZW4uYWNjZXNzX3Rva2VuKTtcbiAgICAgICAgICogICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHN1Y2Nlc3M6ICQubm9vcCB9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBpZiAoIWh0dHBPcHRpb25zLnVzZXJOYW1lIHx8ICFodHRwT3B0aW9ucy5wYXNzd29yZCkge1xuICAgICAgICAgICAgICAgIHZhciByZXNwID0geyBzdGF0dXM6IDQwMSwgc3RhdHVzTWVzc2FnZTogJ05vIHVzZXJuYW1lIG9yIHBhc3N3b3JkIHNwZWNpZmllZC4nIH07XG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvci5jYWxsKHRoaXMsIHJlc3ApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVqZWN0KHJlc3ApLnByb21pc2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHBvc3RQYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgdXNlck5hbWU6IGh0dHBPcHRpb25zLnVzZXJOYW1lLFxuICAgICAgICAgICAgICAgIHBhc3N3b3JkOiBodHRwT3B0aW9ucy5wYXNzd29yZCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoaHR0cE9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vcGFzcyBpbiBudWxsIGZvciBhY2NvdW50IHVuZGVyIG9wdGlvbnMgaWYgeW91IGRvbid0IHdhbnQgaXQgdG8gYmUgc2VudFxuICAgICAgICAgICAgICAgIHBvc3RQYXJhbXMuYWNjb3VudCA9IGh0dHBPcHRpb25zLmFjY291bnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocG9zdFBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2dzIHVzZXIgb3V0IGZyb20gc3BlY2lmaWVkIGFjY291bnRzLlxuICAgICAgICAgKiBFcGljZW50ZXIgbG9nb3V0IGlzIG5vdCBpbXBsZW1lbnRlZCB5ZXQsIGFkZGVkIGEgZHVtbXkgcHJvbWlzZSB0aGF0IGdldHMgYXV0b21hdGljYWxseSByZXNvbHZlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBhdXRoLmxvZ291dCgpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2dvdXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgZHRkLnJlc29sdmUoKTtcbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqICMjIENoYW5uZWwgU2VydmljZVxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBDaGFubmVsIFNlcnZpY2UgaXMgYSBidWlsZGluZyBibG9jayBmb3IgdGhpcyBmdW5jdGlvbmFsaXR5LiBJdCBjcmVhdGVzIGEgcHVibGlzaC1zdWJzY3JpYmUgb2JqZWN0LCBhbGxvd2luZyB5b3UgdG8gcHVibGlzaCBtZXNzYWdlcywgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzLCBvciB1bnN1YnNjcmliZSBmcm9tIG1lc3NhZ2VzIGZvciBhIGdpdmVuICd0b3BpYycgb24gYSBgJC5jb21ldGRgIHRyYW5zcG9ydCBpbnN0YW5jZS5cbiAqXG4gKiBUeXBpY2FsbHksIHlvdSB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgdG8gY3JlYXRlIG9yIHJldHJpZXZlIGNoYW5uZWxzLCB0aGVuIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gbGlzdGVuIHRvIG9yIHVwZGF0ZSBkYXRhLiAoRm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZCBvbiBFcGljZW50ZXIncyBwdXNoIGNoYW5uZWwsIHNlZSB0aGUgaW50cm9kdWN0b3J5IG5vdGVzIG9uIHRoZSBbUHVzaCBDaGFubmVsIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvKSBwYWdlLilcbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UuIFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLlxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCwgdGhlbiBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbiAqXG4gKiAgICAgICAgdmFyIGNzID0gbmV3IEYuc2VydmljZS5DaGFubmVsKCk7XG4gKiAgICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgU2VydmljZSBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgU2VydmljZS5cbiAqICogYG9wdGlvbnMuYmFzZWAgVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLnRvcGljUmVzb2x2ZXJgIEEgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgYWxsICd0b3BpY3MnIHBhc3NlZCBpbnRvIHRoZSBgcHVibGlzaGAgYW5kIGBzdWJzY3JpYmVgIG1ldGhvZHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGltcGxlbWVudCB5b3VyIG93biBzZXJpYWxpemUgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGN1c3RvbSBvYmplY3RzIHRvIHRvcGljIG5hbWVzLiBSZXR1cm5zIGEgU3RyaW5nLiBCeSBkZWZhdWx0LCBpdCBqdXN0IGVjaG9lcyB0aGUgdG9waWMuXG4gKiAqIGBvcHRpb25zLnRyYW5zcG9ydGAgVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLiBTZWUgaHR0cDovL2RvY3MuY29tZXRkLm9yZy9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gY29tZXRkLlxuICovXG52YXIgQ2hhbm5lbCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYmFzZSB0b3BpYy4gVGhpcyBpcyBhZGRlZCBhcyBhIHByZWZpeCB0byBhbGwgZnVydGhlciB0b3BpY3MgeW91IHB1Ymxpc2ggb3Igc3Vic2NyaWJlIHRvIHdoaWxlIHdvcmtpbmcgd2l0aCB0aGlzIENoYW5uZWwgU2VydmljZS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGJhc2U6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqIGB0b3BpY2AgVG9waWMgdG8gcGFyc2UuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiAqU3RyaW5nKjogVGhpcyBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIGEgc3RyaW5nIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICB0b3BpY1Jlc29sdmVyOiBmdW5jdGlvbiAodG9waWMpIHtcbiAgICAgICAgICAgIHJldHVybiB0b3BpYztcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiBudWxsXG4gICAgfTtcbiAgICB0aGlzLmNoYW5uZWxPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbn07XG5cbnZhciBtYWtlTmFtZSA9IGZ1bmN0aW9uIChjaGFubmVsTmFtZSwgdG9waWMpIHtcbiAgICAvL1JlcGxhY2UgdHJhaWxpbmcvZG91YmxlIHNsYXNoZXNcbiAgICB2YXIgbmV3TmFtZSA9IChjaGFubmVsTmFtZSA/IChjaGFubmVsTmFtZSArICcvJyArIHRvcGljKSA6IHRvcGljKS5yZXBsYWNlKC9cXC9cXC8vZywgJy8nKS5yZXBsYWNlKC9cXC8kLywnJyk7XG4gICAgcmV0dXJuIG5ld05hbWU7XG59O1xuXG5cbkNoYW5uZWwucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbC5wcm90b3R5cGUsIHtcblxuICAgIC8vIGZ1dHVyZSBmdW5jdGlvbmFsaXR5OlxuICAgIC8vICAgICAgLy8gU2V0IHRoZSBjb250ZXh0IGZvciB0aGUgY2FsbGJhY2tcbiAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgZnVuY3Rpb24gKCkgeyB0aGlzLmlubmVySFRNTCA9ICdUcmlnZ2VyZWQnfSwgZG9jdW1lbnQuYm9keSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gQ29udHJvbCB0aGUgb3JkZXIgb2Ygb3BlcmF0aW9ucyBieSBzZXR0aW5nIHRoZSBgcHJpb3JpdHlgXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4nLCBjYiwgdGhpcywge3ByaW9yaXR5OiA5fSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIDUwXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiA1MH0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBncmVhdGVyIHRoYW4gNTBcbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6ICc+NTAnfSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIGV2ZW5cbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6IGZ1bmN0aW9uICh2YWwpIHtyZXR1cm4gdmFsICUgMiA9PT0gMH19KTtcblxuXG4gICAgLyoqXG4gICAgICogU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqIFRoZSB0b3BpYyBzaG91bGQgaW5jbHVkZSB0aGUgZnVsbCBwYXRoIG9mIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cyksIHByb2plY3QgaWQsIGFuZCBncm91cCBuYW1lLiAoSW4gbW9zdCBjYXNlcywgaXQgaXMgc2ltcGxlciB0byB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgaW5zdGVhZCwgaW4gd2hpY2ggY2FzZSB0aGlzIGlzIGNvbmZpZ3VyZWQgZm9yIHlvdS4pXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlcyoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjYiA9IGZ1bmN0aW9uKHZhbCkgeyBjb25zb2xlLmxvZyh2YWwuZGF0YSk7IH07XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9wLWxldmVsICdydW4nIHRvcGljXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGNoaWxkcmVuIG9mIHRoZSAncnVuJyB0b3BpYy4gTm90ZSB0aGlzIHdpbGwgYWxzbyBiZSB0cmlnZ2VyZWQgZm9yIGNoYW5nZXMgdG8gcnVuLngueS56LlxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuLyonLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGJvdGggdGhlIHRvcC1sZXZlbCAncnVuJyB0b3BpYyBhbmQgaXRzIGNoaWxkcmVuXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoWycvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJyxcbiAgICAgKiAgICAgICAgICAnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJ10sIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSBwYXJ0aWN1bGFyIHZhcmlhYmxlXG4gICAgICogICAgICBzdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzL3ByaWNlJywgY2IpO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpTdHJpbmcqIFJldHVybnMgYSB0b2tlbiB5b3UgY2FuIGxhdGVyIHVzZSB0byB1bnN1YnNjcmliZS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfEFycmF5fSAgIGB0b3BpY2AgICAgTGlzdCBvZiB0b3BpY3MgdG8gbGlzdGVuIGZvciBjaGFuZ2VzIG9uLlxuICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBgY2FsbGJhY2tgIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGV4ZWN1dGUuIENhbGxiYWNrIGlzIGNhbGxlZCB3aXRoIHNpZ25hdHVyZSBgKGV2dCwgcGF5bG9hZCwgbWV0YWRhdGEpYC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgYGNvbnRleHRgICBDb250ZXh0IGluIHdoaWNoIHRoZSBgY2FsbGJhY2tgIGlzIGV4ZWN1dGVkLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gICBgb3B0aW9uc2AgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICogQHBhcmFtICB7TnVtYmVyfSAgIGBvcHRpb25zLnByaW9yaXR5YCAgVXNlZCB0byBjb250cm9sIG9yZGVyIG9mIG9wZXJhdGlvbnMuIERlZmF1bHRzIHRvIDAuIENhbiBiZSBhbnkgK3ZlIG9yIC12ZSBudW1iZXIuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE51bWJlcnxGdW5jdGlvbn0gICBgb3B0aW9ucy52YWx1ZWAgVGhlIGBjYWxsYmFja2AgaXMgb25seSB0cmlnZ2VyZWQgaWYgdGhpcyBjb25kaXRpb24gbWF0Y2hlcy4gU2VlIGV4YW1wbGVzIGZvciBkZXRhaWxzLlxuICAgICAqXG4gICAgICovXG4gICAgc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9waWMsIGNhbGxiYWNrLCBjb250ZXh0LCBvcHRpb25zKSB7XG5cbiAgICAgICAgdmFyIHRvcGljcyA9IFtdLmNvbmNhdCh0b3BpYyk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBzdWJzY3JpcHRpb25JZHMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuICAgICAgICBvcHRzLnRyYW5zcG9ydC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkLmVhY2godG9waWNzLCBmdW5jdGlvbiAoaW5kZXgsIHRvcGljKSB7XG4gICAgICAgICAgICAgICAgdG9waWMgPSBtYWtlTmFtZShvcHRzLmJhc2UsIG9wdHMudG9waWNSZXNvbHZlcih0b3BpYykpO1xuICAgICAgICAgICAgICAgIHN1YnNjcmlwdGlvbklkcy5wdXNoKG9wdHMudHJhbnNwb3J0LnN1YnNjcmliZSh0b3BpYywgY2FsbGJhY2spKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChzdWJzY3JpcHRpb25JZHNbMV0gPyBzdWJzY3JpcHRpb25JZHMgOiBzdWJzY3JpcHRpb25JZHNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBQdWJsaXNoIGRhdGEgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICAvLyBTZW5kIGRhdGEgdG8gYWxsIHN1YnNjcmliZXJzIG9mIHRoZSAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsIHsgY29tcGxldGVkOiBmYWxzZSB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bi92YXJpYWJsZXMnIHRvcGljXG4gICAgICogICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcycsIHsgcHJpY2U6IDUwIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRvcGljYCBUb3BpYyB0byBwdWJsaXNoIHRvLlxuICAgICAqIEBwYXJhbSAgeyp9IGBkYXRhYCAgRGF0YSB0byBwdWJsaXNoIHRvIHRvcGljLlxuICAgICAqXG4gICAgICovXG4gICAgcHVibGlzaDogZnVuY3Rpb24gKHRvcGljLCBkYXRhKSB7XG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgcmV0dXJuT2JqcyA9IFtdO1xuICAgICAgICB2YXIgb3B0cyA9IG1lLmNoYW5uZWxPcHRpb25zO1xuXG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBpZiAodG9waWMuY2hhckF0KHRvcGljLmxlbmd0aCAtIDEpID09PSAnKicpIHtcbiAgICAgICAgICAgICAgICAgICAgdG9waWMgPSB0b3BpYy5yZXBsYWNlKC9cXCorJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdZb3UgY2FuIGNhbm5vdCBwdWJsaXNoIHRvIGNoYW5uZWxzIHdpdGggd2lsZGNhcmRzLiBQdWJsaXNoaW5nIHRvICcsIHRvcGljLCAnaW5zdGVhZCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpzLnB1c2gob3B0cy50cmFuc3BvcnQucHVibGlzaCh0b3BpYywgZGF0YSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKHJldHVybk9ianNbMV0gPyByZXR1cm5PYmpzIDogcmV0dXJuT2Jqc1swXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVuc3Vic2NyaWJlIGZyb20gY2hhbmdlcyB0byBhIHRvcGljLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgY3MudW5zdWJzY3JpYmUoJ3NhbXBsZVRva2VuJyk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRva2VuYCBUaGUgdG9rZW4gZm9yIHRvcGljIGlzIHJldHVybmVkIHdoZW4geW91IGluaXRpYWxseSBzdWJzY3JpYmUuIFBhc3MgaXQgaGVyZSB0byB1bnN1YnNjcmliZSBmcm9tIHRoYXQgdG9waWMuXG4gICAgICovXG4gICAgdW5zdWJzY3JpYmU6IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICB0aGlzLmNoYW5uZWxPcHRpb25zLnRyYW5zcG9ydC51bnN1YnNjcmliZSh0b2tlbik7XG4gICAgICAgIHJldHVybiB0b2tlbjtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICpcbiAgICAgKiBTdXBwb3J0ZWQgZXZlbnRzIGFyZTogYGNvbm5lY3RgLCBgZGlzY29ubmVjdGAsIGBzdWJzY3JpYmVgLCBgdW5zdWJzY3JpYmVgLCBgcHVibGlzaGAsIGBlcnJvcmAuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqL1xuICAgIG9uOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vbi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdG9wIGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqL1xuICAgIG9mZjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub2ZmLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZXZlbnRzIGFuZCBleGVjdXRlIGhhbmRsZXJzLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqL1xuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENoYW5uZWw7XG4iLCIvKipcbiAqIEBjbGFzcyBDb25maWd1cmF0aW9uU2VydmljZVxuICpcbiAqIEFsbCBzZXJ2aWNlcyB0YWtlIGluIGEgY29uZmlndXJhdGlvbiBzZXR0aW5ncyBvYmplY3QgdG8gY29uZmlndXJlIHRoZW1zZWx2ZXMuIEEgSlMgaGFzaCB7fSBpcyBhIHZhbGlkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCBidXQgb3B0aW9uYWxseSB5b3UgY2FuIHVzZSB0aGUgY29uZmlndXJhdGlvbiBzZXJ2aWNlIHRvIHRvZ2dsZSBjb25maWdzIGJhc2VkIG9uIHRoZSBlbnZpcm9ubWVudFxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgdmFyIGNzID0gcmVxdWlyZSgnY29uZmlndXJhdGlvbi1zZXJ2aWNlJykoe1xuICogICAgICAgICAgZGV2OiB7IC8vZW52aXJvbm1lbnRcbiAgICAgICAgICAgICAgICBwb3J0OiAzMDAwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdsb2NhbGhvc3QnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHByb2Q6IHtcbiAgICAgICAgICAgICAgICBwb3J0OiA4MDgwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgICAgICAgICBsb2dMZXZlbDogJ25vbmUnXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbG9nTGV2ZWw6ICdERUJVRycgLy9nbG9iYWxcbiAqICAgICB9KTtcbiAqXG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudignZGV2Jyk7XG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudigncHJvZCcpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnbm9uZSdcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHVybFNlcnZpY2UgPSByZXF1aXJlKCcuL3VybC1jb25maWctc2VydmljZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IEVudmlyb25tZW50c1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgbG9nTGV2ZWw6ICdOT05FJ1xuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHNlcnZpY2VPcHRpb25zLnNlcnZlciA9IHVybFNlcnZpY2Uoc2VydmljZU9wdGlvbnMuc2VydmVyKTtcblxuICAgIHJldHVybiB7XG5cbiAgICAgICAgZGF0YTogc2VydmljZU9wdGlvbnMsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgZW52aXJvbm1lbnQga2V5IHRvIGdldCBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbVxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGVudlxuICAgICAgICAgKi9cbiAgICAgICAgc2V0RW52OiBmdW5jdGlvbiAoZW52KSB7XG5cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHByb3BlcnR5IG9wdGlvbmFsXG4gICAgICAgICAqIEByZXR1cm4geyp9ICAgICAgICAgIFZhbHVlIG9mIHByb3BlcnR5IGlmIHNwZWNpZmllZCwgdGhlIGVudGlyZSBjb25maWcgb2JqZWN0IG90aGVyd2lzZVxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9uc1twcm9wZXJ0eV07XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5IGlmIGEga2V5IGlzIHByb3ZpZGVkLCBzZXQgYSBrZXkgdG8gdGhhdCB2YWx1ZS4gT3RoZXJ3aXNlIG1lcmdlIG9iamVjdCB3aXRoIGN1cnJlbnQgY29uZmlnXG4gICAgICAgICAqIEBwYXJhbSAgeyp9IHZhbHVlICB2YWx1ZSBmb3IgcHJvdmlkZWQga2V5XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9uc1trZXldID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9O1xufTtcblxuIiwiLyoqXG4gKiAjI0RhdGEgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgRGF0YSBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgbWFuaXB1bGF0ZSBkYXRhIHJlbGF0ZWQgdG8gYW55IG9mIHlvdXIgcHJvamVjdHMuIERhdGEgYXJlIG9yZ2FuaXplZCBpbiBjb2xsZWN0aW9ucy4gRWFjaCBjb2xsZWN0aW9uIGNvbnRhaW5zIGEgZG9jdW1lbnQ7IGVhY2ggZWxlbWVudCBvZiB0aGlzIHRvcC1sZXZlbCBkb2N1bWVudCBpcyBhIEpTT04gb2JqZWN0LiAoU2VlIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gb24gdGhlIHVuZGVybHlpbmcgW0RhdGEgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvZGF0YV9hcGkvKS4pXG4gKlxuICogQWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgRGF0YSBBUEkgU2VydmljZSBkZWZhdWx0cy4gSW4gcGFydGljdWxhciwgdGhlcmUgYXJlIHRocmVlIHJlcXVpcmVkIHBhcmFtZXRlcnMgd2hlbiB5b3UgaW5zdGFudGlhdGUgdGhlIERhdGEgU2VydmljZTpcbiAqXG4gKiAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgcHJvamVjdGA6IEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICogKiBgcm9vdGA6IFRoZSB0aGUgbmFtZSBvZiB0aGUgY29sbGVjdGlvbi4gSWYgeW91IGhhdmUgbXVsdGlwbGUgY29sbGVjdGlvbnMgd2l0aGluIGVhY2ggb2YgeW91ciBwcm9qZWN0cywgeW91IGNhbiBhbHNvIHBhc3MgdGhlIGNvbGxlY3Rpb24gbmFtZSBhcyBhbiBvcHRpb24gZm9yIGVhY2ggY2FsbC5cbiAqXG4gKiAgICAgICB2YXIgZHMgPSBuZXcgRi5zZXJ2aWNlLkRhdGEoe1xuICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgIHJvb3Q6ICdzdXJ2ZXktcmVzcG9uc2VzJyxcbiAqICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBkcy5zYXZlQXMoJ3VzZXIxJyxcbiAqICAgICAgICAgIHsgJ3F1ZXN0aW9uMSc6IDIsICdxdWVzdGlvbjInOiAxMCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiBmYWxzZSwgJ3F1ZXN0aW9uNCc6ICdzb21ldGltZXMnIH0gKTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjInLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMywgJ3F1ZXN0aW9uMic6IDgsXG4gKiAgICAgICAgICAncXVlc3Rpb24zJzogdHJ1ZSwgJ3F1ZXN0aW9uNCc6ICdhbHdheXMnIH0gKTtcbiAqICAgICAgIGRzLnF1ZXJ5KCcnLHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICpcbiAqIE5vdGUgdGhhdCBpbiBhZGRpdGlvbiB0byB0aGUgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgcm9vdGAsIHRoZSBEYXRhIFNlcnZpY2UgcGFyYW1ldGVycyBvcHRpb25hbGx5IGluY2x1ZGUgYSBgc2VydmVyYCBvYmplY3QsIHdob3NlIGBob3N0YCBmaWVsZCBjb250YWlucyB0aGUgVVJJIG9mIHRoZSBGb3JpbyBzZXJ2ZXIuIFRoaXMgaXMgYXV0b21hdGljYWxseSBzZXQsIGJ1dCB5b3UgY2FuIHBhc3MgaXQgZXhwbGljaXRseSBpZiBkZXNpcmVkLiBJdCBpcyBtb3N0IGNvbW1vbmx5IHVzZWQgZm9yIGNsYXJpdHkgd2hlbiB5b3UgYXJlIFtob3N0aW5nIGFuIEVwaWNlbnRlciBwcm9qZWN0IG9uIHlvdXIgb3duIHNlcnZlcl0oLi4vLi4vLi4vaG93X3RvL3NlbGZfaG9zdGluZy8pLlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogTmFtZSBvZiBjb2xsZWN0aW9uLiBEZWZhdWx0cyB0byBgL2AsIHRoYXQgaXMsIHRoZSByb290IGxldmVsIG9mIHlvdXIgcHJvamVjdCBhdCBgZm9yaW8uY29tL2FwcC95b3VyLWFjY291bnQtaWQveW91ci1wcm9qZWN0LWlkL2AuIFJlcXVpcmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcm9vdDogJy8nLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIG9wZXJhdGlvbnMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIGRvbWFpbjogJ2ZvcmlvLmNvbScsXG5cbiAgICAgICAgLy9PcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoa2V5LCByb290KSB7XG4gICAgICAgIGlmICghcm9vdCkge1xuICAgICAgICAgICAgcm9vdCA9IHNlcnZpY2VPcHRpb25zLnJvb3Q7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdkYXRhJykgKyBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKHJvb3QpO1xuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICB1cmwrPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBUaGUgbmFtZSBvZiB0aGUgZG9jdW1lbnQgdG8gc2VhcmNoLiBQYXNzIHRoZSBlbXB0eSBzdHJpbmcgKCcnKSB0byBzZWFyY2ggdGhlIGVudGlyZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHF1ZXJ5YCBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgdG8gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHtxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBrZXlgIElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWx1ZWAgKE9wdGlvbmFsKSBUaGUgZGF0YSB0byBzYXZlLiBJZiBga2V5YCBpcyBhIHN0cmluZywgdGhpcyBpcyB0aGUgdmFsdWUgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgdmFsdWUocykgdG8gc2F2ZSBhcmUgYWxyZWFkeSBwYXJ0IG9mIGBrZXlgIGFuZCB0aGlzIGFyZ3VtZW50IGlzIG5vdCByZXF1aXJlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhIG5hbWVkIGRvY3VtZW50IG9yIGVsZW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHNlcGFyYXRlbHkgaW4gY29uZmlndXJhdGlvbiBvcHRpb25zLCBlaXRoZXIgYXMgcGFydCBvZiB0aGUgY2FsbCBvciBhcyBwYXJ0IG9mIHRoZSBpbml0aWFsaXphdGlvbiBvZiBkcy5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYGtleWAgSWQgb2YgdGhlIGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYGtleWAgVGhlIGlkIG9mIHRoZSBkYXRhIHRvIHJldHVybi4gQ2FuIGJlIHRoZSBpZCBvZiBhIGRvY3VtZW50LCBvciBhIHBhdGggdG8gZGF0YSB3aXRoaW4gdGhhdCBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChrZXksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBkYXRhIGZyb20gY29sbGVjdGlvbi4gT25seSBkb2N1bWVudHMgKHRvcC1sZXZlbCBlbGVtZW50cyBpbiBlYWNoIGNvbGxlY3Rpb24pIGNhbiBiZSBkZWxldGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgZHMucmVtb3ZlKCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xBcnJheX0gYGtleXNgIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBwYXJhbXM7XG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KGtleXMpKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBpZDoga2V5cyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSAnJztcbiAgICAgICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5cywgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFcGljZW50ZXIgZG9lc24ndCBhbGxvdyBudWtpbmcgY29sbGVjdGlvbnNcbiAgICAgICAgLy8gICAgIC8qKlxuICAgICAgICAvLyAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgLy8gICAgICAqIEByZXR1cm4gbnVsbFxuICAgICAgICAvLyAgICAgICovXG4gICAgICAgIC8vICAgICBkZXN0cm95OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgnJywgb3B0aW9ucyk7XG4gICAgICAgIC8vICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyNNZW1iZXIgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgTWVtYmVyIEFQSSBBZGFwdGVyIHByb3ZpZGVzIG1ldGhvZHMgdG8gbG9vayB1cCBpbmZvcm1hdGlvbiBhYm91dCBlbmQgdXNlcnMgZm9yIHlvdXIgcHJvamVjdCBhbmQgaG93IHRoZXkgYXJlIGRpdmlkZWQgYWNyb3NzIGdyb3Vwcy4gSXQgaXMgYmFzZWQgb24gcXVlcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW01lbWJlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvbWVtYmVyLykuXG4gKlxuICogVGhpcyBpcyBvbmx5IG5lZWRlZCBmb3IgQXV0aGVudGljYXRlZCBwcm9qZWN0cywgdGhhdCBpcywgdGVhbSBwcm9qZWN0cyB3aXRoIFtlbmQgdXNlcnMgYW5kIGdyb3Vwc10oLi4vLi4vLi4vZ3JvdXBzX2FuZF9lbmRfdXNlcnMvKS4gRm9yIGV4YW1wbGUsIGlmIHNvbWUgb2YgeW91ciBlbmQgdXNlcnMgYXJlIGZhY2lsaXRhdG9ycywgb3IgaWYgeW91ciBlbmQgdXNlcnMgc2hvdWxkIGJlIHRyZWF0ZWQgZGlmZmVyZW50bHkgYmFzZWQgb24gd2hpY2ggZ3JvdXAgdGhleSBhcmUgaW4sIHVzZSB0aGUgTWVtYmVyIEFQSSB0byBmaW5kIHRoYXQgaW5mb3JtYXRpb24uXG4gKlxuICogICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gKiAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICdiNmIzMTNhMy1hYjg0LTQ3OWMtYmFlYS0yMDZmNmJmZjMzNycgfSk7XG4gKiAgICAgIG1hLmdldEdyb3VwRGV0YWlscyh7IGdyb3VwSWQ6ICcwMGI1MzMwOC05ODMzLTQ3ZjItYjIxZS0xMjc4YzA3ZDUzYjgnIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGFwaUVuZHBvaW50ID0gJ21lbWJlci9sb2NhbCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciB1c2VyIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBncm91cCBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuIE5vdGUgdGhhdCB0aGlzIGlzIHRoZSBncm91cCAqaWQqLCBub3QgdGhlIGdyb3VwICpuYW1lKi5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGdyb3VwSWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucywgc2VydmljZU9wdGlvbnMpO1xuXG4gICAgdmFyIGdldEZpbmFsUGFyYW1zID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBwYXRjaFVzZXJBY3RpdmVGaWVsZCA9IGZ1bmN0aW9uIChwYXJhbXMsIGFjdGl2ZSwgb3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBwYXJhbXMuZ3JvdXBJZCArICcvJyArIHBhcmFtcy51c2VySWRcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goeyBhY3RpdmU6IGFjdGl2ZSB9LCBodHRwT3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBhbGwgb2YgdGhlIGdyb3VwIG1lbWJlcnNoaXBzIGZvciBvbmUgZW5kIHVzZXIuIFRoZSBtZW1iZXJzaGlwIGRldGFpbHMgYXJlIHJldHVybmVkIGluIGFuIGFycmF5LCB3aXRoIG9uZSBlbGVtZW50IChncm91cCByZWNvcmQpIGZvciBlYWNoIGdyb3VwIHRvIHdoaWNoIHRoZSBlbmQgdXNlciBiZWxvbmdzLlxuICAgICAgICAqXG4gICAgICAgICogSW4gdGhlIG1lbWJlcnNoaXAgYXJyYXksIGVhY2ggZ3JvdXAgcmVjb3JkIGluY2x1ZGVzIHRoZSBncm91cCBpZCwgcHJvamVjdCBpZCwgYWNjb3VudCAodGVhbSkgaWQsIGFuZCBhbiBhcnJheSBvZiBtZW1iZXJzLiBIb3dldmVyLCBvbmx5IHRoZSB1c2VyIHdob3NlIHVzZXJJZCBpcyBpbmNsdWRlZCBpbiB0aGUgY2FsbCBpcyBsaXN0ZWQgaW4gdGhlIG1lbWJlcnMgYXJyYXkgKHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGVyZSBhcmUgb3RoZXIgbWVtYmVycyBpbiB0aGlzIGdyb3VwKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcignNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24obWVtYmVyc2hpcHMpe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPG1lbWJlcnNoaXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cobWVtYmVyc2hpcHNbaV0uZ3JvdXBJZCk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gYHBhcmFtc2AgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlci4gQWx0ZXJuYXRpdmVseSwgYW4gb2JqZWN0IHdpdGggZmllbGQgYHVzZXJJZGAgYW5kIHZhbHVlIHRoZSB1c2VyIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRHcm91cHNGb3JVc2VyOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB1c2VySWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ2V0UGFybXMgPSBpc1N0cmluZyA/IHsgdXNlcklkOiBwYXJhbXMgfSA6IF9waWNrKG9ialBhcmFtcywgJ3VzZXJJZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldFBhcm1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBvbmUgZ3JvdXAsIGluY2x1ZGluZyBhbiBhcnJheSBvZiBhbGwgaXRzIG1lbWJlcnMuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3VwRGV0YWlscygnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZ3JvdXApe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPGdyb3VwLm1lbWJlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhncm91cC5tZW1iZXJzW2ldLnVzZXJOYW1lKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIH1cbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoeyBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fSBgcGFyYW1zYCBUaGUgZ3JvdXAgaWQuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGBncm91cElkYCBhbmQgdmFsdWUgdGhlIGdyb3VwIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0R3JvdXBEZXRhaWxzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMuZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZ3JvdXBJZCBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBncm91cElkID0gaXNTdHJpbmcgPyBwYXJhbXMgOiBvYmpQYXJhbXMuZ3JvdXBJZDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIGdyb3VwSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgYWN0aXZlYC4gQWN0aXZlIGVuZCB1c2VycyBjYW4gYmUgYXNzaWduZWQgdG8gW3dvcmxkc10oLi4vd29ybGQtbWFuYWdlci8pIGluIG11bHRpcGxheWVyIGdhbWVzIGR1cmluZyBhdXRvbWF0aWMgYXNzaWdubWVudC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEubWFrZVVzZXJBY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIG1ha2VVc2VyQWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCB0cnVlLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBTZXQgYSBwYXJ0aWN1bGFyIGVuZCB1c2VyIGFzIGBpbmFjdGl2ZWAuIEluYWN0aXZlIGVuZCB1c2VycyBhcmUgbm90IGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VySW5hY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggdGhpcyBlbmQgdXNlciBiZWxvbmdzLCBhbmQgaW4gd2hpY2ggdGhlIGVuZCB1c2VyIHNob3VsZCBiZWNvbWUgaW5hY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckluYWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCBmYWxzZSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI1J1biBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBSdW4gQVBJIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBwZXJmb3JtIGNvbW1vbiB0YXNrcyBhcm91bmQgY3JlYXRpbmcgYW5kIHVwZGF0aW5nIHJ1bnMsIHZhcmlhYmxlcywgYW5kIGRhdGEuXG4gKlxuICogV2hlbiBidWlsZGluZyBpbnRlcmZhY2VzIHRvIHNob3cgcnVuIG9uZSBhdCBhIHRpbWUgKGFzIGZvciBzdGFuZGFyZCBlbmQgdXNlcnMpLCB0eXBpY2FsbHkgeW91IGZpcnN0IGluc3RhbnRpYXRlIGEgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGFuZCB0aGVuIGFjY2VzcyB0aGUgUnVuIFNlcnZpY2UgdGhhdCBpcyBhdXRvbWF0aWNhbGx5IHBhcnQgb2YgdGhlIG1hbmFnZXIsIHJhdGhlciB0aGFuIGluc3RhbnRpYXRpbmcgdGhlIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LiBUaGlzIGlzIGJlY2F1c2UgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLlxuICpcbiAqIEhvd2V2ZXIsIG1hbnkgb2YgdGhlIEVwaWNlbnRlciBzYW1wbGUgcHJvamVjdHMgdXNlIGEgUnVuIFNlcnZpY2UsIGJlY2F1c2UgZ2VuZXJhbGx5IHRoZSBzYW1wbGUgcHJvamVjdHMgYXJlIHBsYXllZCBpbiBvbmUgZW5kIHVzZXIgc2Vzc2lvbiBhbmQgZG9uJ3QgY2FyZSBhYm91dCBydW4gc3RhdGVzIG9yIFtydW4gc3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKS4gVGhlIFJ1biBBUEkgU2VydmljZSBpcyBhbHNvIHVzZWZ1bCBmb3IgYnVpbGRpbmcgYW4gaW50ZXJmYWNlIGZvciBhIGZhY2lsaXRhdG9yLCBiZWNhdXNlIGl0IG1ha2VzIGl0IGVhc3kgdG8gbGlzdCBkYXRhIGFjcm9zcyBtdWx0aXBsZSBydW5zICh1c2luZyB0aGUgYGZpbHRlcigpYCBhbmQgYHF1ZXJ5KClgIG1ldGhvZHMpLlxuICpcbiAqIFRvIHVzZSB0aGUgUnVuIEFQSSBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKlxuICogRm9yIGV4YW1wbGUsXG4gKlxuICogICAgICAgdmFyIHJzID0gbmV3IEYuc2VydmljZS5SdW4oe1xuICogICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgIH0pO1xuICogICAgICBycy5jcmVhdGUoJ3N1cHBseV9jaGFpbl9nYW1lLnB5JykudGhlbihmdW5jdGlvbihydW4pIHtcbiAqICAgICAgICAgICAgIHJzLmRvKCdzb21lT3BlcmF0aW9uJyk7XG4gKiAgICAgIH0pO1xuICpcbiAqXG4gKiBBZGRpdGlvbmFsbHksIGFsbCBBUEkgY2FsbHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFJ1biBBUEkgU2VydmljZSBkZWZhdWx0cyBsaXN0ZWQgYmVsb3cuXG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGBtb2RlbGAsIHRoZSBSdW4gU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKlxuICogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiAqICAgICAgICAgICBydW46IHtcbiAqICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseV9jaGFpbl9nYW1lLnB5JyxcbiAqICAgICAgICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICAgICAgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBybS5nZXRSdW4oKVxuICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBSdW4gU2VydmljZSxcbiAqICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4gKiAgICAgICAgICAgICAgIHZhciBycyA9IHJtLnJ1bjtcbiAqICAgICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgIH0pXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgVmFyaWFibGVzU2VydmljZSA9IHJlcXVpcmUoJy4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8IHN0b3JlLmdldCgnZXBpY2VudGVyLnRva2VuJykgfHwgJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgcnVucy4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlci5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRmxhZyBkZXRlcm1pbmVzIGlmIGBYLUF1dG9SZXN0b3JlOiB0cnVlYCBoZWFkZXIgaXMgc2VudCB0byBFcGljZW50ZXIuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBhdXRvUmVzdG9yZTogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuICAgIHVybENvbmZpZy5nZXRGaWx0ZXJVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJyk7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBxdXRpbC50b01hdHJpeEZvcm1hdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpO1xuXG4gICAgICAgIGlmIChmaWx0ZXIpIHtcbiAgICAgICAgICAgIHVybCArPSBmaWx0ZXIgKyAnLyc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmZpbHRlcjtcbiAgICAgICAgLy8gVGhlIHNlbWljb2xvbiBzZXBhcmF0ZWQgZmlsdGVyIGlzIHVzZWQgd2hlbiBmaWx0ZXIgaXMgYW4gb2JqZWN0XG4gICAgICAgIHZhciBpc0ZpbHRlclJ1bklkID0gZmlsdGVyICYmICQudHlwZShmaWx0ZXIpID09PSAnc3RyaW5nJztcbiAgICAgICAgaWYgKHNlcnZpY2VPcHRpb25zLmF1dG9SZXN0b3JlICYmIGlzRmlsdGVyUnVuSWQpIHtcbiAgICAgICAgICAgIC8vIEJ5IGRlZmF1bHQgYXV0b3JlcGxheSB0aGUgcnVuIGJ5IHNlbmRpbmcgdGhpcyBoZWFkZXIgdG8gZXBpY2VudGVyXG4gICAgICAgICAgICAvLyBodHRwczovL2ZvcmlvLmNvbS9lcGljZW50ZXIvZG9jcy9wdWJsaWMvcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNyZXRyaWV2aW5nXG4gICAgICAgICAgICB2YXIgYXV0b3Jlc3RvcmVPcHRzID0ge1xuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJ1gtQXV0b1Jlc3RvcmUnOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBhdXRvcmVzdG9yZU9wdHMsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgc2V0RmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBmaWx0ZXIgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgdXJsQ29uZmlnOiB1cmxDb25maWcsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyZWF0ZSBhIG5ldyBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIE5PVEU6IFR5cGljYWxseSB0aGlzIGlzIG5vdCB1c2VkISBVc2UgYFJ1bk1hbmFnZXIuZ2V0UnVuKClgIHdpdGggYSBgc3RyYXRlZ3lgIG9mIGBhbHdheXMtbmV3YCwgb3IgdXNlIGBSdW5NYW5hZ2VyLnJlc2V0KClgLiBTZWUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHJzLmNyZWF0ZSgnaGVsbG9fd29ybGQuamwnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYHBhcmFtc2AgSWYgYSBzdHJpbmcsIHRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IFttb2RlbCBmaWxlXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4gVGhpcyBpcyB0aGUgb25lIGZpbGUgaW4gdGhlIHByb2plY3QgdGhhdCBleHBsaWNpdGx5IGV4cG9zZXMgdmFyaWFibGVzIGFuZCBtZXRob2RzLCBhbmQgaXQgbXVzdCBiZSBzdG9yZWQgaW4gdGhlIE1vZGVsIGZvbGRlciBvZiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBJZiBhbiBvYmplY3QsIG1heSBpbmNsdWRlIGBtb2RlbGAsIGBzY29wZWAsIGFuZCBgZmlsZXNgLiAoU2VlIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bl9tYW5hZ2VyLykgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gYHNjb3BlYCBhbmQgYGZpbGVzYC4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICpcbiAgICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJykgfSk7XG4gICAgICAgICAgICB2YXIgcnVuQXBpUGFyYW1zID0gWydtb2RlbCcsICdzY29wZScsICdmaWxlcyddO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gdGhpcyBpcyBqdXN0IHRoZSBtb2RlbCBuYW1lXG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBtb2RlbDogcGFyYW1zIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHdoaXRlbGlzdCB0aGUgZmllbGRzIHRoYXQgd2UgYWN0dWFsbHkgY2FuIHNlbmQgdG8gdGhlIGFwaVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgcnVuQXBpUGFyYW1zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGVsZW1lbnRzIG9mIHRoZSBgcXNgIG9iamVjdCBhcmUgQU5EZWQgdG9nZXRoZXIgd2l0aGluIGEgc2luZ2xlIGNhbGwgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZXR1cm5zIHJ1bnMgd2l0aCBzYXZlZCA9IHRydWUgYW5kIHZhcmlhYmxlcy5wcmljZSA+IDEsXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgdmFyaWFibGVzLnByaWNlIGhhcyBiZWVuIHBlcnNpc3RlZCAocmVjb3JkZWQpXG4gICAgICAgICAqICAgICAgLy8gaW4gdGhlIG1vZGVsLlxuICAgICAgICAgKiAgICAgcnMucXVlcnkoe1xuICAgICAgICAgKiAgICAgICAgICAnc2F2ZWQnOiAndHJ1ZScsXG4gICAgICAgICAqICAgICAgICAgICcucHJpY2UnOiAnPjEnXG4gICAgICAgICAqICAgICAgIH0sXG4gICAgICAgICAqICAgICAgIHtcbiAgICAgICAgICogICAgICAgICAgc3RhcnRyZWNvcmQ6IDIsXG4gICAgICAgICAqICAgICAgICAgIGVuZHJlY29yZDogNVxuICAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBxc2AgUXVlcnkgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBRdWVyeWluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXMsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBxczsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFNpbWlsYXIgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJgIEZpbHRlciBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIEZpbHRlcmluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogZnVuY3Rpb24gKGZpbHRlciwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qoc2VydmljZU9wdGlvbnMuZmlsdGVyKSkge1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlcnZpY2VPcHRpb25zLmZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gZmlsdGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBkYXRhIGZvciBhIHNwZWNpZmljIHJ1bi4gVGhpcyBpbmNsdWRlcyBzdGFuZGFyZCBydW4gZGF0YSBzdWNoIGFzIHRoZSBhY2NvdW50LCBtb2RlbCwgcHJvamVjdCwgYW5kIGNyZWF0ZWQgYW5kIGxhc3QgbW9kaWZpZWQgZGF0ZXMuIFRvIHJlcXVlc3Qgc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLCBwYXNzIHRoZW0gYXMgcGFydCBvZiB0aGUgYGZpbHRlcnNgIHBhcmFtZXRlci5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IGlmIHRoZSBydW4gaXMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSksIGFueSBtb2RlbCB2YXJpYWJsZXMgYXJlIGF2YWlsYWJsZTsgaWYgdGhlIHJ1biBpcyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLCBvbmx5IG1vZGVsIHZhcmlhYmxlcyB0aGF0IGhhdmUgYmVlbiBwZXJzaXN0ZWQgJm1kYXNoOyB0aGF0IGlzLCBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwgJm1kYXNoOyBhcmUgYXZhaWxhYmxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgcnMubG9hZCgnYmI1ODk2NzctZDQ3Ni00OTcxLWE2OGUtMGM1OGQxOTFlNDUwJywgeyBpbmNsdWRlOiBbJy5wcmljZScsICcuc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBydW5JRGAgVGhlIHJ1biBpZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJzYCAoT3B0aW9uYWwpIE9iamVjdCBjb250YWluaW5nIGZpbHRlcnMgYW5kIG9wZXJhdGlvbiBtb2RpZmllcnMuIFVzZSBrZXkgYGluY2x1ZGVgIHRvIGxpc3QgbW9kZWwgdmFyaWFibGVzIHRoYXQgeW91IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUgcmVzcG9uc2UuIE90aGVyIGF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAocnVuSUQsIGZpbHRlcnMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmIChydW5JRCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJ1bklEOyAvL3Nob3VsZG4ndCBiZSBhYmxlIHRvIG92ZXItcmlkZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBhdHRyaWJ1dGVzIChkYXRhLCBtb2RlbCB2YXJpYWJsZXMpIG9mIHRoZSBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gYWRkICdjb21wbGV0ZWQnIGZpZWxkIHRvIHJ1biByZWNvcmRcbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBjb21wbGV0ZWQ6IHRydWUgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyB1cGRhdGUgJ3NhdmVkJyBmaWVsZCBvZiBydW4gcmVjb3JkLCBhbmQgdXBkYXRlIHZhbHVlcyBvZiBtb2RlbCB2YXJpYWJsZXMgZm9yIHRoaXMgcnVuXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgc2F2ZWQ6IHRydWUsIHZhcmlhYmxlczogeyBhOiAyMywgYjogMjMgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBhdHRyaWJ1dGVzYCBUaGUgcnVuIGRhdGEgYW5kIHZhcmlhYmxlcyB0byBzYXZlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGF0dHJpYnV0ZXMudmFyaWFibGVzYCBNb2RlbCB2YXJpYWJsZXMgbXVzdCBiZSBpbmNsdWRlZCBpbiBhIGB2YXJpYWJsZXNgIGZpZWxkIHdpdGhpbiB0aGUgYGF0dHJpYnV0ZXNgIG9iamVjdC4gKE90aGVyd2lzZSB0aGV5IGFyZSB0cmVhdGVkIGFzIHJ1biBkYXRhIGFuZCBhZGRlZCB0byB0aGUgcnVuIHJlY29yZCBkaXJlY3RseS4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uIChhdHRyaWJ1dGVzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKGF0dHJpYnV0ZXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBhIG1ldGhvZCBmcm9tIHRoZSBtb2RlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2QgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGBwYXJhbXNgIGFyZ3VtZW50IGlzIG5vcm1hbGx5IGFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byB0aGUgYG9wZXJhdGlvbmAuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXkuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCB5b3UgY2FuIGNvbWJpbmUgdGhlIGBvcGVyYXRpb25gIGFuZCBgcGFyYW1zYCBhcmd1bWVudHMgaW50byBhIHNpbmdsZSBvYmplY3QgaWYgeW91IHByZWZlciwgYXMgaW4gdGhlIGxhc3QgZXhhbXBsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic29sdmVcIiB0YWtlcyBubyBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLmRvKCdzb2x2ZScpO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsIFsnaGVsbG8nXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgJ2hlbGxvJyk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic3VtQXJyYXlcIiB0YWtlcyBvbmUgYXJndW1lbnQsIGFuIGFycmF5XG4gICAgICAgICAqICAgICBycy5kbygnc3VtQXJyYXknLCBbWzQsMiwxXV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImFkZFwiIHRha2VzIHR3byBhcmd1bWVudHMsIGJvdGggaW50ZWdlcnNcbiAgICAgICAgICogICAgIHJzLmRvKHsgbmFtZTonYWRkJywgcGFyYW1zOlsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYG9wZXJhdGlvbmAgTmFtZSBvZiBtZXRob2QuXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBwYXJhbXNgIChPcHRpb25hbCkgQW55IHBhcmFtZXRlcnMgdGhlIG9wZXJhdGlvbiB0YWtlcywgcGFzc2VkIGFzIGFuIGFycmF5LiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LCBhbmQgY2FuIGp1c3QgcGFzcyBpdCBkaXJlY3RseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZG86IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ2RvJywgb3BlcmF0aW9uLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wc0FyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnM7XG4gICAgICAgICAgICBpZiAob3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICAgICAgb3BzQXJncyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9uLCBvcHNBcmdzKTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgcG9zdE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcHJtcyA9IChyZXN1bHQuYXJnc1swXS5sZW5ndGggJiYgKHJlc3VsdC5hcmdzWzBdICE9PSBudWxsICYmIHJlc3VsdC5hcmdzWzBdICE9PSB1bmRlZmluZWQpKSA/IHJlc3VsdC5hcmdzWzBdIDogW107XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgYXJndW1lbnRzOiBwcm1zIH0sICQuZXh0ZW5kKHRydWUsIHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ29wZXJhdGlvbnMvJyArIHJlc3VsdC5vcHNbMF0gKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwsIHNlcXVlbnRpYWxseS5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2RzIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0aWFsaXplXCIgYW5kIFwic29sdmVcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWydpbml0aWFsaXplJywgJ3NvbHZlJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0XCIgYW5kIFwicmVzZXRcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncmVzZXQnLCBwYXJhbXM6IFsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJpbml0XCIgdGFrZXMgdHdvIGFyZ3VtZW50cyxcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJydW5tb2RlbFwiIHRha2VzIG5vbmVcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3J1bm1vZGVsJywgcGFyYW1zOiBbXSB9XSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBvcGVyYXRpb25zYCBJZiBub25lIG9mIHRoZSBtZXRob2RzIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgbWV0aG9kIG5hbWVzIChzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBtZXRob2RzIGRvIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGEgbWV0aG9kIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzZXJpYWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9TaW5nbGVPcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgb3AgPSBvcHMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICB2YXIgYXJnID0gYXJncy5zaGlmdCgpO1xuXG4gICAgICAgICAgICAgICAgbWUuZG8ob3AsIGFyZywge1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob3BzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbCwgZXhlY3V0aW5nIHRoZW0gaW4gcGFyYWxsZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kcyBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJzb2x2ZVwiIGFuZCBcInJlc2V0XCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWydzb2x2ZScsICdyZXNldCddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWyB7IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3N1YnRyYWN0JywgcGFyYW1zOlsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoeyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fSBgb3BlcmF0aW9uc2AgSWYgbm9uZSBvZiB0aGUgbWV0aG9kcyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG1ldGhvZCBuYW1lcyAoYXMgc3RyaW5ncykuIElmIGFueSBvZiB0aGUgbWV0aG9kcyBkbyB0YWtlIHBhcmFtZXRlcnMsIHlvdSBoYXZlIHR3byBvcHRpb25zLiBZb3UgY2FuIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhIG1ldGhvZCBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBwYXNzIGEgc2luZ2xlIG9iamVjdCB3aXRoIHRoZSBtZXRob2QgbmFtZSBhbmQgYSAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFsbGVsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG5cbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcXVldWUgID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaTwgb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcXVldWUucHVzaChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kbyhvcHNbaV0sIGFyZ3NbaV0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICQud2hlbi5hcHBseSh0aGlzLCBxdWV1ZSlcbiAgICAgICAgICAgICAgICAuZG9uZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2Vzcy5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvci5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY1N5bmNBUEkgPSB7XG4gICAgICAgIGdldEN1cnJlbnRDb25maWc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgfSxcbiAgICAgICAgLyoqXG4gICAgICAgICAgKiBSZXR1cm5zIGEgVmFyaWFibGVzIFNlcnZpY2UgaW5zdGFuY2UuIFVzZSB0aGUgdmFyaWFibGVzIGluc3RhbmNlIHRvIGxvYWQsIHNhdmUsIGFuZCBxdWVyeSBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLiBTZWUgdGhlIFtWYXJpYWJsZSBBUEkgU2VydmljZV0oLi4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAgICAgICAgKlxuICAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAgICAgIHZhciB2cyA9IHJzLnZhcmlhYmxlcygpO1xuICAgICAgICAgICogICAgICB2cy5zYXZlKHsgc2FtcGxlX2ludDogNCB9KTtcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBjb25maWdgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAgKi9cbiAgICAgICAgdmFyaWFibGVzOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgdnMgPSBuZXcgVmFyaWFibGVzU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZywge1xuICAgICAgICAgICAgICAgIHJ1blNlcnZpY2U6IHRoaXNcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIHJldHVybiB2cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljU3luY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4gKiAjI1N0YXRlIEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIFN0YXRlIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gcmVwbGF5IG9yIGNsb25lIHJ1bnMuIEl0IGJyaW5ncyBleGlzdGluZywgcGVyc2lzdGVkIHJ1biBkYXRhIGZyb20gdGhlIGRhdGFiYXNlIGJhY2sgaW50byBtZW1vcnksIHVzaW5nIHRoZSBzYW1lIHJ1biBpZCAoYHJlcGxheWApIG9yIGEgbmV3IHJ1biBpZCAoYGNsb25lYCkuIFJ1bnMgbXVzdCBiZSBpbiBtZW1vcnkgaW4gb3JkZXIgZm9yIHlvdSB0byB1cGRhdGUgdmFyaWFibGVzIG9yIGNhbGwgb3BlcmF0aW9ucyBvbiB0aGVtLlxuICpcbiAqIFNwZWNpZmljYWxseSwgdGhlIFN0YXRlIEFQSSBBZGFwdGVyIHdvcmtzIGJ5IFwicmUtcnVubmluZ1wiIHRoZSBydW4gKHVzZXIgaW50ZXJhY3Rpb25zKSBmcm9tIHRoZSBjcmVhdGlvbiBvZiB0aGUgcnVuIHVwIHRvIHRoZSB0aW1lIGl0IHdhcyBsYXN0IHBlcnNpc3RlZCBpbiB0aGUgZGF0YWJhc2UuIFRoaXMgcHJvY2VzcyB1c2VzIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIHJ1bidzIG1vZGVsLiBUaGVyZWZvcmUsIGlmIHRoZSBtb2RlbCBoYXMgY2hhbmdlZCBzaW5jZSB0aGUgb3JpZ2luYWwgcnVuIHdhcyBjcmVhdGVkLCB0aGUgcmV0cmlldmVkIHJ1biB3aWxsIHVzZSB0aGUgbmV3IG1vZGVsIOKAlCBhbmQgbWF5IGVuZCB1cCBoYXZpbmcgZGlmZmVyZW50IHZhbHVlcyBvciBiZWhhdmlvciBhcyBhIHJlc3VsdC4gVXNlIHdpdGggY2FyZSFcbiAqXG4gKiBUbyB1c2UgdGhlIFN0YXRlIEFQSSBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBjYWxsIGl0cyBtZXRob2RzOlxuICpcbiAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJ30pO1xuICpcbiAqIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgcHJvamVjdGAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4gKlxuICovXG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBhcGlFbmRwb2ludCA9ICdtb2RlbC9zdGF0ZSc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgfTtcblxuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcbiAgICB2YXIgcGFyc2VSdW5JZE9yRXJyb3IgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSAmJiBwYXJhbXMucnVuSWQpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbXMucnVuSWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwYXNzIGluIGEgcnVuIGlkJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGF5IGEgcnVuLiBBZnRlciB0aGlzIGNhbGwsIHRoZSBydW4sIHdpdGggaXRzIG9yaWdpbmFsIHJ1biBpZCwgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gKEl0IGNvbnRpbnVlcyB0byBiZSBwZXJzaXN0ZWQgaW50byB0aGUgRXBpY2VudGVyIGRhdGFiYXNlIGF0IHJlZ3VsYXIgaW50ZXJ2YWxzLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJywgc3RvcEJlZm9yZTogJ2NhbGN1bGF0ZVNjb3JlJ30pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBicmluZyBiYWNrIHRvIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBgcGFyYW1zLmV4Y2x1ZGVgIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZXBsYXk6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdyZXBsYXknIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ2xvbmUgYSBnaXZlbiBydW4gYW5kIHJldHVybiBhIG5ldyBydW4gaW4gdGhlIHNhbWUgc3RhdGUgYXMgdGhlIGdpdmVuIHJ1bi5cbiAgICAgICAgKlxuICAgICAgICAqIFRoZSBuZXcgcnVuIGlkIGlzIG5vdyBhdmFpbGFibGUgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIFRoZSBuZXcgcnVuIGluY2x1ZGVzIGEgY29weSBvZiBhbGwgb2YgdGhlIGRhdGEgZnJvbSB0aGUgb3JpZ2luYWwgcnVuLCBFWENFUFQ6XG4gICAgICAgICpcbiAgICAgICAgKiAqIFRoZSBgc2F2ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAuXG4gICAgICAgICogKiBUaGUgYGluaXRpYWxpemVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgbm90IGNvcGllZCBmcm9tIHRoZSBvcmlnaW5hbCBydW4gcmVjb3JkLiBJdCBkZWZhdWx0cyB0byBgZmFsc2VgIGJ1dCBtYXkgY2hhbmdlIHRvIGB0cnVlYCBhcyB0aGUgbmV3IHJ1biBpcyBhZHZhbmNlZC4gRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGhhcyBiZWVuIGEgY2FsbCB0byB0aGUgYHN0ZXBgIGZ1bmN0aW9uIChmb3IgVmVuc2ltIG1vZGVscyksIHRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGlzIHNldCB0byBgdHJ1ZWAuXG4gICAgICAgICogKiBUaGUgYGNyZWF0ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyB0aGUgZGF0ZSBhbmQgdGltZSBhdCB3aGljaCB0aGUgY2xvbmUgd2FzIGNyZWF0ZWQgKG5vdCB0aGUgdGltZSB0aGF0IHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQuKVxuICAgICAgICAqXG4gICAgICAgICogVGhlIG9yaWdpbmFsIHJ1biByZW1haW5zIG9ubHkgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLWRiKS5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5jbG9uZSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnLCBleGNsdWRlOiBbJ2ludGVyaW1DYWxjdWxhdGlvbiddIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBjbG9uZSBmcm9tIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBuZXdseSBjbG9uZWQgcnVuIGlzIGFkdmFuY2VkIG9ubHkgdXAgdG8gdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgdGhpcyBtZXRob2QuXG4gICAgICAgICogQHBhcmFtIHthcnJheX0gYHBhcmFtcy5leGNsdWRlYCAoT3B0aW9uYWwpIEFycmF5IG9mIG1ldGhvZHMgdG8gZXhjbHVkZSB3aGVuIGFkdmFuY2luZyB0aGUgbmV3bHkgY2xvbmVkIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGNsb25lOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcnVuSWQgPSBwYXJzZVJ1bklkT3JFcnJvcihwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgcmVwbGF5T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHJ1bklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgYWN0aW9uOiAnY2xvbmUnIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBlcGlWZXJzaW9uID0gcmVxdWlyZSgnLi4vYXBpLXZlcnNpb24uanNvbicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IHVybHV0aWxzIHRvIGdldCBob3N0LCBzaW5jZSBubyB3aW5kb3cgb24gbm9kZVxuXG4gICAgdmFyIEFQSV9QUk9UT0NPTCA9ICdodHRwcyc7XG4gICAgdmFyIEhPU1RfQVBJX01BUFBJTkcgPSB7XG4gICAgICAgICdmb3Jpby5jb20nOiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICdmb3Jpb2Rldi5jb20nOiAnYXBpLmVwaWNlbnRlci5mb3Jpb2Rldi5jb20nXG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNFeHBvcnRzID0ge1xuICAgICAgICBwcm90b2NvbDogQVBJX1BST1RPQ09MLFxuXG4gICAgICAgIGFwaTogJycsXG5cbiAgICAgICAgaG9zdDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICBpZiAoIWhvc3QgfHwgaG9zdC5pbmRleE9mKCdsb2NhbCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGhvc3QgPSAnZm9yaW8uY29tJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAoSE9TVF9BUElfTUFQUElOR1tob3N0XSkgPyBIT1NUX0FQSV9NQVBQSU5HW2hvc3RdIDogJ2FwaS4nICsgaG9zdDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBhcHBQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gcGF0aCAmJiBwYXRoWzFdIHx8ICcnO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFjY291bnRQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFjY250ID0gJyc7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIGFjY250ID0gcGF0aFsyXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhY2NudDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBwcm9qZWN0UGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwcmogPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIGlmIChwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnKSB7XG4gICAgICAgICAgICAgICAgcHJqID0gcGF0aFszXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBwcmo7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgdmVyc2lvblBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgdmVyc2lvbiA9IGVwaVZlcnNpb24udmVyc2lvbiA/IGVwaVZlcnNpb24udmVyc2lvbiArICcvJyA6ICcnO1xuICAgICAgICAgICAgcmV0dXJuIHZlcnNpb247XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgaXNMb2NhbGhvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICByZXR1cm4gKCFob3N0IHx8IGhvc3QuaW5kZXhPZignbG9jYWwnKSAhPT0gLTEpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGdldEFQSVBhdGg6IGZ1bmN0aW9uIChhcGkpIHtcbiAgICAgICAgICAgIHZhciBQUk9KRUNUX0FQSVMgPSBbJ3J1bicsICdkYXRhJywgJ2ZpbGUnXTtcblxuICAgICAgICAgICAgdmFyIGFwaVBhdGggPSB0aGlzLnByb3RvY29sICsgJzovLycgKyB0aGlzLmhvc3QgKyAnLycgKyB0aGlzLnZlcnNpb25QYXRoICsgYXBpICsgJy8nO1xuXG4gICAgICAgICAgICBpZiAoJC5pbkFycmF5KGFwaSwgUFJPSkVDVF9BUElTKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBhcGlQYXRoICs9IHRoaXMuYWNjb3VudFBhdGggKyAnLycgKyB0aGlzLnByb2plY3RQYXRoICArICcvJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhcGlQYXRoO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHB1YmxpY0V4cG9ydHMsIGNvbmZpZyk7XG4gICAgcmV0dXJuIHB1YmxpY0V4cG9ydHM7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4qICMjVXNlciBBUEkgQWRhcHRlclxuKlxuKiBUaGUgVXNlciBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHJldHJpZXZlIGRldGFpbHMgYWJvdXQgZW5kIHVzZXJzIGluIHlvdXIgdGVhbSAoYWNjb3VudCkuIEl0IGlzIGJhc2VkIG9uIHRoZSBxdWVyeWluZyBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbVXNlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvdXNlci8pLlxuKlxuKiBUbyB1c2UgdGhlIFVzZXIgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHMuXG4qXG4qICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nXG4qICAgICAgIH0pO1xuKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiogICAgICAgdWEuZ2V0KHsgdXNlck5hbWU6ICdqc21pdGgnIH0pO1xuKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4qXG4qIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgdG9rZW5gIGlmIHRoZXkgYXJlIG5vdCBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgY3VycmVudCBjb250ZXh0LlxuKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2Nlc3MgdG9rZW4gdG8gdXNlIHdoZW4gc2VhcmNoaW5nIGZvciBlbmQgdXNlcnMuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgcGFydGljdWxhciBlbmQgdXNlcnMgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIG5hbWUgb3IgdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4gICAgICAgICogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgZmlsdGVyYCBPYmplY3Qgd2l0aCBmaWVsZCBgdXNlck5hbWVgIGFuZCB2YWx1ZSBvZiB0aGUgdXNlcm5hbWUuIEFsdGVybmF0aXZlbHksIG9iamVjdCB3aXRoIGZpZWxkIGBpZGAgYW5kIHZhbHVlIG9mIGFuIGFycmF5IG9mIHVzZXIgaWRzLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWx0ZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciB0b1FGaWx0ZXIgPSBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgLy8gQVBJIG9ubHkgc3VwcG9ydHMgZmlsdGVyaW5nIGJ5IHVzZXJuYW1lIGZvciBub3dcbiAgICAgICAgICAgICAgICBpZiAoZmlsdGVyLnVzZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5xID0gZmlsdGVyLnVzZXJOYW1lO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgdG9JZEZpbHRlcnMgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZCA9ICQuaXNBcnJheShpZCkgPyBpZCA6IFtpZF07XG4gICAgICAgICAgICAgICAgcmV0dXJuICdpZD0nICsgaWQuam9pbignJmlkPScpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIGdldEZpbHRlcnMgPSBbXG4gICAgICAgICAgICAgICAgJ2FjY291bnQ9JyArIGdldE9wdGlvbnMuYWNjb3VudCxcbiAgICAgICAgICAgICAgICB0b0lkRmlsdGVycyhmaWx0ZXIuaWQpLFxuICAgICAgICAgICAgICAgIHF1dGlsLnRvUXVlcnlGb3JtYXQodG9RRmlsdGVyKGZpbHRlcikpXG4gICAgICAgICAgICBdLmpvaW4oJyYnKTtcblxuICAgICAgICAgICAgLy8gc3BlY2lhbCBjYXNlIGZvciBxdWVyaWVzIHdpdGggbGFyZ2UgbnVtYmVyIG9mIGlkc1xuICAgICAgICAgICAgLy8gbWFrZSBpdCBhcyBhIHBvc3Qgd2l0aCBHRVQgc2VtYW50aWNzXG4gICAgICAgICAgICB2YXIgdGhyZXNob2xkID0gMzA7XG4gICAgICAgICAgICBpZiAoZmlsdGVyLmlkICYmICQuaXNBcnJheShmaWx0ZXIuaWQpICYmIGZpbHRlci5pZC5sZW5ndGggPj0gdGhyZXNob2xkKSB7XG4gICAgICAgICAgICAgICAgZ2V0T3B0aW9ucy51cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpICsgJz9fbWV0aG9kPUdFVCc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGlkOiBmaWx0ZXIuaWQgfSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRGaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGEgc2luZ2xlIGVuZCB1c2VyIGluIHlvdXIgdGVhbSwgYmFzZWQgb24gdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRCeUlkOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcHVibGljQVBJLmdldCh7IGlkOiB1c2VySWQgfSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG5cblxuXG5cbiIsIi8qKlxuICpcbiAqICMjVmFyaWFibGVzIEFQSSBTZXJ2aWNlXG4gKlxuICogVXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSB0byByZWFkLCB3cml0ZSwgYW5kIHNlYXJjaCBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLlxuICpcbiAqICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJ1xuICogICAgICAgICAgIH1cbiAqICAgICAgfSk7XG4gKiAgICAgcm0uZ2V0UnVuKClcbiAqICAgICAgIC50aGVuKGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgdmFyIHZzID0gcm0ucnVuLnZhcmlhYmxlcygpO1xuICogICAgICAgICAgdnMuc2F2ZSh7c2FtcGxlX2ludDogNH0pO1xuICogICAgICAgIH0pO1xuICpcbiAqL1xuXG5cbiAndXNlIHN0cmljdCc7XG5cbiB2YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG4gdmFyIHJ1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9ydW4tdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcnVucyBvYmplY3QgdG8gd2hpY2ggdGhlIHZhcmlhYmxlIGZpbHRlcnMgYXBwbHkuIERlZmF1bHRzIHRvIG51bGwuXG4gICAgICAgICAqIEB0eXBlIHtydW5TZXJ2aWNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcnVuU2VydmljZTogbnVsbFxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ3ZhcmlhYmxlcy8nO1xuICAgIH07XG5cbiAgICB2YXIgYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9IHtcbiAgICAgICAgdXJsOiBnZXRVUkxcbiAgICB9O1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICBodHRwLnNwbGl0R2V0ID0gcnV0aWwuc3BsaXRHZXRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB2YWx1ZXMgZm9yIGEgdmFyaWFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMubG9hZCgnc2FtcGxlX2ludCcpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCl7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgY29udGFpbnMgdGhlIHZhbHVlIG9mIHNhbXBsZV9pbnRcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgdmFyaWFibGVgIE5hbWUgb2YgdmFyaWFibGUgdG8gbG9hZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHZhcmlhYmxlLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG91dHB1dE1vZGlmaWVyLCAkLmV4dGVuZCh7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IGdldFVSTCgpICsgdmFyaWFibGUgKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHZhcmlhYmxlcywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxdWVyeWAgb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KFsncHJpY2UnLCAnc2FsZXMnXSlcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgaXMgYW4gb2JqZWN0IHdpdGggdGhlIHZhbHVlcyBvZiB0aGUgcmVxdWVzdGVkIHZhcmlhYmxlczogdmFsLnByaWNlLCB2YWwuc2FsZXNcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoeyBpbmNsdWRlOlsncHJpY2UnLCAnc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IGBxdWVyeWAgVGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgcmVxdWVzdGVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9RdWVyeSBhbmQgb3V0cHV0TW9kaWZpZXIgYXJlIGJvdGggcXVlcnlzdHJpbmdzIGluIHRoZSB1cmw7IG9ubHkgY2FsbGluZyB0aGVtIG91dCBzZXBhcmF0ZWx5IGhlcmUgdG8gYmUgY29uc2lzdGVudCB3aXRoIHRoZSBvdGhlciBjYWxsc1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KHF1ZXJ5KSkge1xuICAgICAgICAgICAgICAgIHF1ZXJ5ID0geyBpbmNsdWRlOiBxdWVyeSB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJC5leHRlbmQocXVlcnksIG91dHB1dE1vZGlmaWVyKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KHF1ZXJ5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgdmFsdWVzIHRvIG1vZGVsIHZhcmlhYmxlcy4gT3ZlcndyaXRlcyBleGlzdGluZyB2YWx1ZXMuIE5vdGUgdGhhdCB5b3UgY2FuIG9ubHkgdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoQW4gYWx0ZXJuYXRlIHdheSB0byB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlzIHRvIGNhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwgYW5kIG1ha2Ugc3VyZSB0aGF0IHRoZSBtZXRob2QgcGVyc2lzdHMgdGhlIHZhcmlhYmxlcy4gU2VlIGBkb2AsIGBzZXJpYWxgLCBhbmQgYHBhcmFsbGVsYCBpbiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgZm9yIGNhbGxpbmcgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMuc2F2ZSgncHJpY2UnLCA0KTtcbiAgICAgICAgICogICAgICB2cy5zYXZlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgdmFyaWFibGVgIEFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgbW9kZWwgdmFyaWFibGVzIGFuZCB0aGUgdmFsdWVzIHRvIHNhdmUuIEFsdGVybmF0aXZlbHksIGEgc3RyaW5nIHdpdGggdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbGAgKE9wdGlvbmFsKSBJZiBwYXNzaW5nIGEgc3RyaW5nIGZvciBgdmFyaWFibGVgLCB1c2UgdGhpcyBhcmd1bWVudCBmb3IgdGhlIHZhbHVlIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uICh2YXJpYWJsZSwgdmFsLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW3ZhcmlhYmxlXSA9IHZhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoLmNhbGwodGhpcywgYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdCBBdmFpbGFibGUgdW50aWwgdW5kZXJseWluZyBBUEkgc3VwcG9ydHMgUFVULiBPdGhlcndpc2Ugc2F2ZSB3b3VsZCBiZSBQVVQgYW5kIG1lcmdlIHdvdWxkIGJlIFBBVENIXG4gICAgICAgIC8vICpcbiAgICAgICAgLy8gICogU2F2ZSB2YWx1ZXMgdG8gdGhlIGFwaS4gTWVyZ2VzIGFycmF5cywgYnV0IG90aGVyd2lzZSBzYW1lIGFzIHNhdmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSB2YXJpYWJsZSBPYmplY3Qgd2l0aCBhdHRyaWJ1dGVzLCBvciBzdHJpbmcga2V5XG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSB2YWwgT3B0aW9uYWwgaWYgcHJldiBwYXJhbWV0ZXIgd2FzIGEgc3RyaW5nLCBzZXQgdmFsdWUgaGVyZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAZXhhbXBsZVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSgncHJpY2UnLCA0KTtcblxuICAgICAgICAvLyBtZXJnZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgLy8gICAgIHZhciBhdHRycztcbiAgICAgICAgLy8gICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIC8vICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgIC8vICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAvLyAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAvLyAgICAgfVxuICAgICAgICAvLyAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAvLyAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICAvLyB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNXb3JsZCBBUEkgQWRhcHRlclxuICpcbiAqIEEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsIC0tIGluY2x1ZGluZyBzZXR0aW5nIHZhcmlhYmxlcywgbWFraW5nIGRlY2lzaW9ucywgYW5kIGNhbGxpbmcgb3BlcmF0aW9ucy4gRm9yIGJ1aWxkaW5nIG11bHRpcGxheWVyIHNpbXVsYXRpb25zIHlvdSB0eXBpY2FsbHkgd2FudCBtdWx0aXBsZSBlbmQgdXNlcnMgdG8gc2hhcmUgdGhlIHNhbWUgc2V0IG9mIGludGVyYWN0aW9ucywgYW5kIHdvcmsgd2l0aGluIGEgY29tbW9uIHN0YXRlLiBFcGljZW50ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUgXCJ3b3JsZHNcIiB0byBoYW5kbGUgc3VjaCBjYXNlcy4gT25seSBbdGVhbSBwcm9qZWN0c10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIGNhbiBiZSBtdWx0aXBsYXllci5cbiAqXG4gKiBUaGUgV29ybGQgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUsIGFjY2VzcywgYW5kIG1hbmlwdWxhdGUgbXVsdGlwbGF5ZXIgd29ybGRzIHdpdGhpbiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBZb3UgY2FuIHVzZSB0aGlzIHRvIGFkZCBhbmQgcmVtb3ZlIGVuZCB1c2VycyBmcm9tIHRoZSB3b3JsZCwgYW5kIHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgcmVtb3ZlIHRoZWlyIHJ1bnMuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4gKFRoZSByZWxhdGVkIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyLykgcHJvdmlkZXMgYW4gZWFzeSB3YXkgdG8gYWNjZXNzIHJ1bnMgYW5kIHdvcmxkcyBmb3IgcGFydGljdWxhciBlbmQgdXNlcnMsIHNvIGlzIHR5cGljYWxseSB1c2VkIGluIHBhZ2VzIHRoYXQgZW5kIHVzZXJzIHdpbGwgaW50ZXJhY3Qgd2l0aC4pXG4gKlxuICogQXMgd2l0aCBhbGwgdGhlIG90aGVyIFtBUEkgQWRhcHRlcnNdKC4uLy4uLyksIGFsbCBtZXRob2RzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBXb3JsZCBBUEkgU2VydmljZSBkZWZhdWx0cy5cbiAqXG4gKiBUbyB1c2UgdGhlIFdvcmxkIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSksIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKSwgYW5kIGdyb3VwICgqKkdyb3VwIE5hbWUqKikuXG4gKlxuICogICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gKiAgICAgICB3YS5jcmVhdGUoKVxuICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAqICAgICAgICAgICAgICAvLyBjYWxsIG1ldGhvZHMsIGUuZy4gd2EuYWRkVXNlcnMoKVxuICogICAgICAgICAgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG4vLyB2YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGFwaUJhc2UgPSAnbXVsdGlwbGF5ZXIvJztcbnZhciBhc3NpZ25tZW50RW5kcG9pbnQgPSBhcGlCYXNlICsgJ2Fzc2lnbic7XG52YXIgYXBpRW5kcG9pbnQgPSBhcGlCYXNlICsgJ3dvcmxkJztcbnZhciBwcm9qZWN0RW5kcG9pbnQgPSBhcGlCYXNlICsgJ3Byb2plY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkoeyBzeW5jaHJvbm91czogdHJ1ZSB9KTtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgZ3JvdXA6IHVuZGVmaW5lZCxcblxuICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIHJ1bnMgaW4gdGhpcyB3b3JsZC4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbW9kZWw6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JpdGVyaWEgYnkgd2hpY2ggdG8gZmlsdGVyIHdvcmxkLiBDdXJyZW50bHkgb25seSBzdXBwb3J0cyB3b3JsZC1pZHMgYXMgZmlsdGVycy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlbmllbmNlIGFsaWFzIGZvciBmaWx0ZXJcbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3BcbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMucHJvamVjdCA9IHVybENvbmZpZy5wcm9qZWN0UGF0aDtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBzZXRJZEZpbHRlck9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmlkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gd29ybGQgaWQgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdC4gVGhpcyBjb3VsZCBoYXBwZW4gaWYgdGhlIHVzZXIgaXMgbm90IGFzc2lnbmVkIHRvIGEgd29ybGQgYW5kIGlzIHRyeWluZyB0byB3b3JrIHdpdGggcnVucyBmcm9tIHRoYXQgd29ybGQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAoIW9wdGlvbnMubW9kZWwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gbW9kZWwgc3BlY2lmaWVkIHRvIGdldCB0aGUgY3VycmVudCBydW4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENyZWF0ZXMgYSBuZXcgV29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBVc2luZyB0aGlzIG1ldGhvZCBpcyByYXJlLiBJdCBpcyBtb3JlIGNvbW1vbiB0byBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkgd2hpbGUgeW91IGBhdXRvQXNzaWduKClgIGVuZCB1c2VycyB0byB3b3JsZHMuIChJbiB0aGlzIGNhc2UsIGNvbmZpZ3VyYXRpb24gZGF0YSBmb3IgdGhlIHdvcmxkLCBzdWNoIGFzIHRoZSByb2xlcywgYXJlIHJlYWQgZnJvbSB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9uLCBmb3IgZXhhbXBsZSBieSBgZ2V0UHJvamVjdFNldHRpbmdzKClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSh7XG4gICAgICAgICogICAgICAgICAgIHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddXG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBjcmVhdGUgdGhlIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwYCAoT3B0aW9uYWwpIFRoZSAqKkdyb3VwIE5hbWUqKiB0byBjcmVhdGUgdGhpcyB3b3JsZCB1bmRlci4gT25seSBlbmQgdXNlcnMgaW4gdGhpcyBncm91cCBhcmUgZWxpZ2libGUgdG8gam9pbiB0aGUgd29ybGQuIE9wdGlvbmFsIGhlcmU7IHJlcXVpcmVkIHdoZW4gaW5zdGFudGlhdGluZyB0aGUgc2VydmljZSAoYG5ldyBGLnNlcnZpY2UuV29ybGQoKWApLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfSk7XG4gICAgICAgICAgICB2YXIgd29ybGRBcGlQYXJhbXMgPSBbJ3Njb3BlJywgJ2ZpbGVzJywgJ3JvbGVzJywgJ29wdGlvbmFsUm9sZXMnLCAnbWluVXNlcnMnLCAnZ3JvdXAnLCAnbmFtZSddO1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHdvcmxkQXBpUGFyYW1zKTtcblxuICAgICAgICAgICAgLy8gYWNjb3VudCBhbmQgcHJvamVjdCBnbyBpbiB0aGUgYm9keSwgbm90IGluIHRoZSB1cmxcbiAgICAgICAgICAgICQuZXh0ZW5kKHBhcmFtcywgX3BpY2soc2VydmljZU9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pKTtcblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBVcGRhdGVzIGEgV29ybGQsIGZvciBleGFtcGxlIHRvIHJlcGxhY2UgdGhlIHJvbGVzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgeW91IGNvbXBsZXRlIHdvcmxkIGNvbmZpZ3VyYXRpb24gYXQgdGhlIHByb2plY3QgbGV2ZWwsIHJhdGhlciB0aGFuIGF0IHRoZSB3b3JsZCBsZXZlbC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguIEhvd2V2ZXIsIHRoaXMgbWV0aG9kIGlzIGF2YWlsYWJsZSBpZiB5b3UgbmVlZCB0byB1cGRhdGUgdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBwYXJ0aWN1bGFyIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnVwZGF0ZSh7IHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHVwZGF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMubmFtZWAgQSBzdHJpbmcgaWRlbnRpZmllciBmb3IgdGhlIGxpbmtlZCBlbmQgdXNlcnMsIGZvciBleGFtcGxlLCBcIm5hbWVcIjogXCJPdXIgVGVhbVwiLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHdoaXRlbGlzdCA9IFsncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycyddO1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHVwZGF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zIHx8IHt9LCB3aGl0ZWxpc3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChwYXJhbXMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYW4gZXhpc3Rpbmcgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBUaGlzIGZ1bmN0aW9uIG9wdGlvbmFsbHkgdGFrZXMgb25lIGFyZ3VtZW50LiBJZiB0aGUgYXJndW1lbnQgaXMgYSBzdHJpbmcsIGl0IGlzIHRoZSBpZCBvZiB0aGUgd29ybGQgdG8gZGVsZXRlLiBJZiB0aGUgYXJndW1lbnQgaXMgYW4gb2JqZWN0LCBpdCBpcyB0aGUgb3ZlcnJpZGUgZm9yIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmRlbGV0ZSgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUsIG9yIG9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAob3B0aW9ucyAmJiAodHlwZW9mIG9wdGlvbnMgPT09ICdzdHJpbmcnKSkgPyB7IGZpbHRlcjogb3B0aW9ucyB9IDoge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRlbGV0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGRlbGV0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBjdXJyZW50IGluc3RhbmNlIG9mIHRoZSBXb3JsZCBBUEkgQWRhcHRlciAoaW5jbHVkaW5nIGFsbCBzdWJzZXF1ZW50IGZ1bmN0aW9uIGNhbGxzLCB1bnRpbCB0aGUgY29uZmlndXJhdGlvbiBpcyB1cGRhdGVkIGFnYWluKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoey4uLn0pLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogJzEyMycgfSkuYWRkVXNlcih7IHVzZXJJZDogJzEyMycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgY29uZmlnYCBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gdXNlIGluIHVwZGF0aW5nIGV4aXN0aW5nIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZUNvbmZpZzogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMsIGNvbmZpZyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIExpc3RzIGFsbCB3b3JsZHMgZm9yIGEgZ2l2ZW4gYWNjb3VudCwgcHJvamVjdCwgYW5kIGdyb3VwLiBBbGwgdGhyZWUgYXJlIHJlcXVpcmVkLCBhbmQgaWYgbm90IHNwZWNpZmllZCBhcyBwYXJhbWV0ZXJzLCBhcmUgcmVhZCBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJ0ZWFtMVwiXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5saXN0KCk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJvdGhlci1ncm91cC1uYW1lXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoeyBncm91cDogJ290aGVyLWdyb3VwLW5hbWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBsaXN0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGFsbCB3b3JsZHMgdGhhdCBhbiBlbmQgdXNlciBiZWxvbmdzIHRvIGZvciBhIGdpdmVuIGFjY291bnQgKHRlYW0pLCBwcm9qZWN0LCBhbmQgZ3JvdXAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZ2V0V29ybGRzRm9yVXNlcignYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJylcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZHMgYXJlIGJlaW5nIHJldHJpZXZlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldFdvcmxkc0ZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YXIgZmlsdGVycyA9ICQuZXh0ZW5kKFxuICAgICAgICAgICAgICAgIF9waWNrKGdldE9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pLFxuICAgICAgICAgICAgICAgIHsgdXNlcklkOiB1c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGluZm9ybWF0aW9uIGZvciBhIHNwZWNpZmljIHdvcmxkLiBBbGwgZnVydGhlciBjYWxscyB0byB0aGUgd29ybGQgc2VydmljZSB3aWxsIHVzZSB0aGUgaWQgcHJvdmlkZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgd29ybGRJZGAgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBsb2FkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgd29ybGRpZCB0byBsb2FkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy8nIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQWRkcyBhbiBlbmQgdXNlciBvciBsaXN0IG9mIGVuZCB1c2VycyB0byBhIGdpdmVuIHdvcmxkLiBUaGUgZW5kIHVzZXIgbXVzdCBiZSBhIG1lbWJlciBvZiB0aGUgYGdyb3VwYCB0aGF0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlclxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoWydiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2Vycyh7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdWUCBTYWxlcycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBzZXZlcmFsIHVzZXJzXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgeyB1c2VySWQ6ICdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ1ZQIE1hcmtldGluZycgfSxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgRW5naW5lZXJpbmcnIH1cbiAgICAgICAgKiAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgICAgICAvLyBhZGQgb25lIHVzZXIgdG8gYSBzcGVjaWZpYyB3b3JsZFxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB7IGZpbHRlcjogd29ybGQuaWQgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdHxhcnJheX0gYHVzZXJzYCBVc2VyIGlkLCBhcnJheSBvZiB1c2VyIGlkcywgb2JqZWN0LCBvciBhcnJheSBvZiBvYmplY3RzIG9mIHRoZSB1c2VycyB0byBhZGQgdG8gdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJzLnJvbGVgIFRoZSBgcm9sZWAgdGhlIHVzZXIgc2hvdWxkIGhhdmUgaW4gdGhlIHdvcmxkLiBJdCBpcyB1cCB0byB0aGUgY2FsbGVyIHRvIGVuc3VyZSwgaWYgbmVlZGVkLCB0aGF0IHRoZSBgcm9sZWAgcGFzc2VkIGluIGlzIG9uZSBvZiB0aGUgYHJvbGVzYCBvciBgb3B0aW9uYWxSb2xlc2Agb2YgdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSB3b3JsZCB0byB3aGljaCB0aGUgdXNlcnMgc2hvdWxkIGJlIGFkZGVkLiBJZiBub3Qgc3BlY2lmaWVkLCB0aGUgZmlsdGVyIHBhcmFtZXRlciBvZiB0aGUgYG9wdGlvbnNgIG9iamVjdCBpcyB1c2VkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgYWRkVXNlcnM6IGZ1bmN0aW9uICh1c2Vycywgd29ybGRJZCwgb3B0aW9ucykge1xuXG4gICAgICAgICAgICBpZiAoIXVzZXJzKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhIGxpc3Qgb2YgdXNlcnMgdG8gYWRkIHRvIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBub3JtYWxpemUgdGhlIGxpc3Qgb2YgdXNlcnMgdG8gYW4gYXJyYXkgb2YgdXNlciBvYmplY3RzXG4gICAgICAgICAgICB1c2VycyA9ICQubWFwKFtdLmNvbmNhdCh1c2VycyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KHUpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1ICE9PSAnc3RyaW5nJyAmJiAhaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTb21lIG9mIHRoZSB1c2VycyBpbiB0aGUgbGlzdCBhcmUgbm90IGluIHRoZSB2YWxpZCBmb3JtYXQ6ICcgKyB1KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gaXNPYmplY3QgPyB1IDogeyB1c2VySWQ6IHUgfTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBjaGVjayBpZiBvcHRpb25zIHdlcmUgcGFzc2VkIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHdvcmxkSWQpICYmICFvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHdvcmxkSWQ7XG4gICAgICAgICAgICAgICAgd29ybGRJZCA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICAvLyB3ZSBtdXN0IGhhdmUgb3B0aW9ucyBieSBub3dcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygd29ybGRJZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvdXNlcnMnIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QodXNlcnMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIHJvbGUgb2YgYW4gZW5kIHVzZXIgaW4gYSBnaXZlbiB3b3JsZC4gKFlvdSBjYW4gb25seSB1cGRhdGUgb25lIGVuZCB1c2VyIGF0IGEgdGltZS4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuY3JlYXRlKCkudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgIHdhLnVwZGF0ZVVzZXIoeyB1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCByb2xlOiAnbGVhZGVyJyB9KTtcbiAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHVzZXJgIFVzZXIgb2JqZWN0IHdpdGggYHVzZXJJZGAgYW5kIHRoZSBuZXcgYHJvbGVgLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICghdXNlciB8fCAhdXNlci51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHBhc3MgYSB1c2VySWQgdG8gdXBkYXRlIGZyb20gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcGF0Y2hPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goX3BpY2sodXNlciwgJ3JvbGUnKSwgcGF0Y2hPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZW1vdmVzIGFuIGVuZCB1c2VyIGZyb20gYSBnaXZlbiB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5yZW1vdmVVc2VyKCdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoeyB1c2VySWQ6ICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdHxzdHJpbmd9IGB1c2VyYCBUaGUgYHVzZXJJZGAgb2YgdGhlIHVzZXIgdG8gcmVtb3ZlIGZyb20gdGhlIHdvcmxkLCBvciBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgYHVzZXJJZGAgZmllbGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdXNlciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICB1c2VyID0geyB1c2VySWQ6IHVzZXIgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHJ1biBpZCBvZiBjdXJyZW50IHJ1biBmb3IgdGhlIGdpdmVuIHdvcmxkLiBJZiB0aGUgd29ybGQgZG9lcyBub3QgaGF2ZSBhIHJ1biwgY3JlYXRlcyBhIG5ldyBvbmUgYW5kIHJldHVybnMgdGhlIHJ1biBpZC5cbiAgICAgICAgKlxuICAgICAgICAqIFJlbWVtYmVyIHRoYXQgYSBbcnVuXSguLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwuIEluIHRoZSBjYXNlIG9mIG11bHRpcGxheWVyIHByb2plY3RzLCB0aGUgcnVuIGlzIHNoYXJlZCBieSBhbGwgZW5kIHVzZXJzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRDdXJyZW50UnVuSWQoeyBtb2RlbDogJ21vZGVsLnB5JyB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRSdW5JZDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3J1bicgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoX3BpY2soZ2V0T3B0aW9ucywgJ21vZGVsJyksIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBmb3IgdGhlIGdpdmVuIGVuZCB1c2VyIGluIHRoZSBnaXZlbiBncm91cC4gQnJpbmdzIHRoaXMgbW9zdCByZWNlbnQgd29ybGQgaW50byBtZW1vcnkgaWYgbmVlZGVkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIHVzZSBkYXRhIGZyb20gd29ybGRcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSBjdXJyZW50IChtb3N0IHJlY2VudCkgd29ybGQgaXMgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cC4gSWYgbm90IHByb3ZpZGVkLCBkZWZhdWx0cyB0byB0aGUgZ3JvdXAgdXNlZCB0byBjcmVhdGUgdGhlIHNlcnZpY2UuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRXb3JsZEZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkc0ZvclVzZXIodXNlcklkLCB7IGdyb3VwOiBncm91cE5hbWUgfSlcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGFzc3VtZSB0aGUgbW9zdCByZWNlbnQgd29ybGQgYXMgdGhlICdhY3RpdmUnIHdvcmxkXG4gICAgICAgICAgICAgICAgICAgIHdvcmxkcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7IHJldHVybiBuZXcgRGF0ZShiLmxhc3RNb2RpZmllZCkgLSBuZXcgRGF0ZShhLmxhc3RNb2RpZmllZCk7IH0pO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VycmVudFdvcmxkID0gd29ybGRzWzBdO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50V29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9ICBjdXJyZW50V29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShjdXJyZW50V29ybGQsIG1lKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIHRoZSBjdXJyZW50IHJ1biBmcm9tIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIChOb3RlIHRoYXQgdGhlIHdvcmxkIGlkIHJlbWFpbnMgcGFydCBvZiB0aGUgcnVuIHJlY29yZCwgaW5kaWNhdGluZyB0aGF0IHRoZSBydW4gd2FzIGZvcm1lcmx5IGFuIGFjdGl2ZSBydW4gZm9yIHRoZSB3b3JsZC4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmRlbGV0ZVJ1bignc2FtcGxlLXdvcmxkLWlkJyk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSBgd29ybGRJZGAgb2YgdGhlIHdvcmxkIGZyb20gd2hpY2ggdGhlIGN1cnJlbnQgcnVuIGlzIGJlaW5nIGRlbGV0ZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGVSdW46IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBydW4gZm9yIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgd2EubmV3UnVuRm9yV29ybGQod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgd29ybGRJZCBpbiB3aGljaCB3ZSBjcmVhdGUgdGhlIG5ldyBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIG5ld1J1bkZvcldvcmxkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGN1cnJlbnRSdW5PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IGZpbHRlcjogd29ybGRJZCB8fCBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IoY3VycmVudFJ1bk9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kZWxldGVSdW4od29ybGRJZCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5nZXRDdXJyZW50UnVuSWQoY3VycmVudFJ1bk9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEFzc2lnbnMgZW5kIHVzZXJzIHRvIHdvcmxkcywgY3JlYXRpbmcgbmV3IHdvcmxkcyBhcyBhcHByb3ByaWF0ZSwgYXV0b21hdGljYWxseS4gQXNzaWducyBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cCwgYW5kIGNyZWF0ZXMgbmV3IHdvcmxkcyBhcyBuZWVkZWQgYmFzZWQgb24gdGhlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbiAocm9sZXMsIG9wdGlvbmFsIHJvbGVzLCBhbmQgbWluaW11bSBlbmQgdXNlcnMgcGVyIHdvcmxkKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5hdXRvQXNzaWduKCk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBhdXRvQXNzaWduOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhc3NpZ25tZW50RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBwYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3B0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgcHJvamVjdDogb3B0LnByb2plY3QsXG4gICAgICAgICAgICAgICAgZ3JvdXA6IG9wdC5ncm91cFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKG9wdC5tYXhVc2Vycykge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5tYXhVc2VycyA9IG9wdC5tYXhVc2VycztcbiAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgb3B0KTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBwcm9qZWN0J3Mgd29ybGQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgZXZlcnkgaW50ZXJhY3Rpb24gd2l0aCB5b3VyIHByb2plY3QgdXNlcyB0aGUgc2FtZSBjb25maWd1cmF0aW9uIG9mIGVhY2ggd29ybGQuIEZvciBleGFtcGxlLCBlYWNoIHdvcmxkIGluIHlvdXIgcHJvamVjdCBwcm9iYWJseSBoYXMgdGhlIHNhbWUgcm9sZXMgZm9yIGVuZCB1c2Vycy4gQW5kIHlvdXIgcHJvamVjdCBpcyBwcm9iYWJseSBlaXRoZXIgY29uZmlndXJlZCBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgc2hhcmUgdGhlIHNhbWUgd29ybGQgKGFuZCBydW4pLCBvciBzbWFsbGVyIHNldHMgb2YgZW5kIHVzZXJzIHNoYXJlIHdvcmxkcyDigJQgYnV0IG5vdCBib3RoLlxuICAgICAgICAqXG4gICAgICAgICogKFRoZSBbTXVsdGlwbGF5ZXIgUHJvamVjdCBSRVNUIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL211bHRpcGxheWVyX3Byb2plY3QvKSBhbGxvd3MgeW91IHRvIHNldCB0aGVzZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb25zLiBUaGUgV29ybGQgQWRhcHRlciBzaW1wbHkgcmV0cmlldmVzIHRoZW0sIGZvciBleGFtcGxlIHNvIHRoZXkgY2FuIGJlIHVzZWQgaW4gYXV0by1hc3NpZ25tZW50IG9mIGVuZCB1c2VycyB0byB3b3JsZHMuKVxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmdldFByb2plY3RTZXR0aW5ncygpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHNldHRpbmdzKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5yb2xlcyk7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5vcHRpb25hbFJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0UHJvamVjdFNldHRpbmdzOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChwcm9qZWN0RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIG9wdC51cmwgKz0gW29wdC5hY2NvdW50LCBvcHQucHJvamVjdF0uam9pbignLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQobnVsbCwgb3B0KTtcbiAgICAgICAgfVxuXG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29va2llIFN0b3JhZ2UgU2VydmljZVxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgIHZhciBwZW9wbGUgPSByZXF1aXJlKCdjb29raWUtc3RvcmUnKSh7IHJvb3Q6ICdwZW9wbGUnIH0pO1xuICAgICAgICBwZW9wbGVcbiAgICAgICAgICAgIC5zYXZlKHtsYXN0TmFtZTogJ3NtaXRoJyB9KVxuXG4gKi9cblxuXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5hbWUgb2YgY29sbGVjdGlvblxuICAgICAgICAgKiBAdHlwZSB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHJvb3Q6ICcvJyxcblxuICAgICAgICBkb21haW46ICcuZm9yaW8uY29tJ1xuICAgIH07XG4gICAgdGhpcy5zZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIC8vICogVEJEXG4gICAgICAgIC8vICAqIFF1ZXJ5IGNvbGxlY3Rpb247IHVzZXMgTW9uZ29EQiBzeW50YXhcbiAgICAgICAgLy8gICogQHNlZSAgPFRCRDogRGF0YSBBUEkgVVJMPlxuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IHFzIFF1ZXJ5IEZpbHRlclxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IGxpbWl0ZXJzIEBzZWUgPFRCRDogdXJsIGZvciBsaW1pdHMsIHBhZ2luZyBldGM+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBleGFtcGxlXG4gICAgICAgIC8vICAqICAgICBjcy5xdWVyeShcbiAgICAgICAgLy8gICogICAgICB7IG5hbWU6ICdKb2huJywgY2xhc3NOYW1lOiAnQ1NDMTAxJyB9LFxuICAgICAgICAvLyAgKiAgICAgIHtsaW1pdDogMTB9XG4gICAgICAgIC8vICAqICAgICApXG5cbiAgICAgICAgLy8gcXVlcnk6IGZ1bmN0aW9uIChxcywgbGltaXRlcnMpIHtcblxuICAgICAgICAvLyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGNvb2tpZSB2YWx1ZVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5ICAgSWYgZ2l2ZW4gYSBrZXkgc2F2ZSB2YWx1ZXMgdW5kZXIgaXQsIGlmIGdpdmVuIGFuIG9iamVjdCBkaXJlY3RseSwgc2F2ZSB0byB0b3AtbGV2ZWwgYXBpXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gdmFsdWUgKE9wdGlvbmFsKVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIHNlcnZpY2Ugb3B0aW9uc1xuICAgICAgICAgKlxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgc2F2ZWQgdmFsdWVcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnNldCgncGVyc29uJywgeyBmaXJzdE5hbWU6ICdqb2huJywgbGFzdE5hbWU6ICdzbWl0aCcgfSk7XG4gICAgICAgICAqICAgICBjcy5zZXQoeyBuYW1lOidzbWl0aCcsIGFnZTonMzInIH0pO1xuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHNldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5zZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSBzZXRPcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2V0T3B0aW9ucy5yb290O1xuXG4gICAgICAgICAgICBkb2N1bWVudC5jb29raWUgPSBlbmNvZGVVUklDb21wb25lbnQoa2V5KSArICc9JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuY29kZVVSSUNvbXBvbmVudCh2YWx1ZSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG5cbiAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9hZCBjb29raWUgdmFsdWVcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSAgIElmIGdpdmVuIGEga2V5IHNhdmUgdmFsdWVzIHVuZGVyIGl0LCBpZiBnaXZlbiBhbiBvYmplY3QgZGlyZWN0bHksIHNhdmUgdG8gdG9wLWxldmVsIGFwaVxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgdmFsdWUgc3RvcmVkXG4gICAgICAgICAqXG4gICAgICAgICAqIEBleGFtcGxlXG4gICAgICAgICAqICAgICBjcy5nZXQoJ3BlcnNvbicpO1xuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgY29va2llUmVnID0gbmV3IFJlZ0V4cCgnKD86KD86XnwuKjspXFxcXHMqJyArIGVuY29kZVVSSUNvbXBvbmVudChrZXkpLnJlcGxhY2UoL1tcXC1cXC5cXCtcXCpdL2csICdcXFxcJCYnKSArICdcXFxccypcXFxcPVxcXFxzKihbXjtdKikuKiQpfF4uKiQnKTtcbiAgICAgICAgICAgIHZhciB2YWwgPSBkb2N1bWVudC5jb29raWUucmVwbGFjZShjb29raWVSZWcsICckMScpO1xuICAgICAgICAgICAgdmFsID0gZGVjb2RlVVJJQ29tcG9uZW50KHZhbCkgfHwgbnVsbDtcbiAgICAgICAgICAgIHJldHVybiB2YWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMga2V5IGZyb20gY29sbGVjdGlvblxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGtleSBrZXkgdG8gcmVtb3ZlXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9IGtleSBUaGUga2V5IHJlbW92ZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnJlbW92ZSgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciByZW1PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMuc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9tYWluID0gcmVtT3B0aW9ucy5kb21haW47XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHJlbU9wdGlvbnMucm9vdDtcblxuICAgICAgICAgICAgZG9jdW1lbnQuY29va2llID0gZW5jb2RlVVJJQ29tcG9uZW50KGtleSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICc9OyBleHBpcmVzPVRodSwgMDEgSmFuIDE5NzAgMDA6MDA6MDAgR01UJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGRvbWFpbiA/ICc7IGRvbWFpbj0nICsgZG9tYWluIDogJycpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG4gICAgICAgICAgICByZXR1cm4ga2V5O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIGNvbGxlY3Rpb24gYmVpbmcgcmVmZXJlbmNlZFxuICAgICAgICAgKiBAcmV0dXJuIHsgYXJyYXl9IGtleXMgQWxsIHRoZSBrZXlzIHJlbW92ZWRcbiAgICAgICAgICovXG4gICAgICAgIGRlc3Ryb3k6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhS2V5cyA9IGRvY3VtZW50LmNvb2tpZS5yZXBsYWNlKC8oKD86XnxcXHMqOylbXlxcPV0rKSg/PTt8JCl8Xlxccyp8XFxzKig/OlxcPVteO10qKT8oPzpcXDF8JCkvZywgJycpLnNwbGl0KC9cXHMqKD86XFw9W147XSopPztcXHMqLyk7XG4gICAgICAgICAgICBmb3IgKHZhciBuSWR4ID0gMDsgbklkeCA8IGFLZXlzLmxlbmd0aDsgbklkeCsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvb2tpZUtleSA9IGRlY29kZVVSSUNvbXBvbmVudChhS2V5c1tuSWR4XSk7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmUoY29va2llS2V5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhS2V5cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICAgIERlY2lkZXMgdHlwZSBvZiBzdG9yZSB0byBwcm92aWRlXG4qL1xuXG4ndXNlIHN0cmljdCc7XG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHN0b3JlID0gKGlzTm9kZSkgPyByZXF1aXJlKCcuL3Nlc3Npb24tc3RvcmUnKSA6IHJlcXVpcmUoJy4vY29va2llLXN0b3JlJyk7XG52YXIgc3RvcmUgPSByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHN0b3JlO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgcXV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgIGhlYWRlcnM6IHt9LFxuICAgICAgICBzdGF0dXNDb2RlOiB7XG4gICAgICAgICAgICA0MDQ6ICQubm9vcFxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPTkxZIGZvciBzdHJpbmdzIGluIHRoZSB1cmwuIEFsbCBHRVQgJiBERUxFVEUgcGFyYW1zIGFyZSBydW4gdGhyb3VnaCB0aGlzXG4gICAgICAgICAqIEB0eXBlIHtbdHlwZV0gfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFyYW1ldGVyUGFyc2VyOiBxdXRpbHMudG9RdWVyeUZvcm1hdCxcblxuICAgICAgICAvLyBUbyBhbGxvdyBlcGljZW50ZXIudG9rZW4gYW5kIG90aGVyIHNlc3Npb24gY29va2llcyB0byBiZSBwYXNzZWRcbiAgICAgICAgLy8gd2l0aCB0aGUgcmVxdWVzdHNcbiAgICAgICAgeGhyRmllbGRzOiB7XG4gICAgICAgICAgICB3aXRoQ3JlZGVudGlhbHM6IHRydWVcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciByZXN1bHQgPSBmdW5jdGlvbiAoZCkge1xuICAgICAgICByZXR1cm4gKCQuaXNGdW5jdGlvbihkKSkgPyBkKCkgOiBkO1xuICAgIH07XG5cbiAgICB2YXIgY29ubmVjdCA9IGZ1bmN0aW9uIChtZXRob2QsIHBhcmFtcywgY29ubmVjdE9wdGlvbnMpIHtcbiAgICAgICAgcGFyYW1zID0gcmVzdWx0KHBhcmFtcyk7XG4gICAgICAgIHBhcmFtcyA9ICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSB8fCAkLmlzQXJyYXkocGFyYW1zKSkgPyBKU09OLnN0cmluZ2lmeShwYXJhbXMpIDogcGFyYW1zO1xuXG4gICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRyYW5zcG9ydE9wdGlvbnMsIGNvbm5lY3RPcHRpb25zLCB7XG4gICAgICAgICAgICB0eXBlOiBtZXRob2QsXG4gICAgICAgICAgICBkYXRhOiBwYXJhbXNcbiAgICAgICAgfSk7XG4gICAgICAgIHZhciBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUyA9IFsnZGF0YScsICd1cmwnXTtcbiAgICAgICAgJC5lYWNoKG9wdGlvbnMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAoJC5pc0Z1bmN0aW9uKHZhbHVlKSAmJiAkLmluQXJyYXkoa2V5LCBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9uc1trZXldID0gdmFsdWUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKG9wdGlvbnMubG9nTGV2ZWwgJiYgb3B0aW9ucy5sb2dMZXZlbCA9PT0gJ0RFQlVHJykge1xuICAgICAgICAgICAgY29uc29sZS5sb2cob3B0aW9ucy51cmwpO1xuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3NGbiA9IG9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UsIGFqYXhTdGF0dXMsIGFqYXhSZXEpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgb2xkU3VjY2Vzc0ZuLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGJlZm9yZVNlbmQgPSBvcHRpb25zLmJlZm9yZVNlbmQ7XG4gICAgICAgIG9wdGlvbnMuYmVmb3JlU2VuZCA9IGZ1bmN0aW9uICh4aHIsIHNldHRpbmdzKSB7XG4gICAgICAgICAgICB4aHIucmVxdWVzdFVybCA9IChjb25uZWN0T3B0aW9ucyB8fCB7fSkudXJsO1xuICAgICAgICAgICAgaWYgKGJlZm9yZVNlbmQpIHtcbiAgICAgICAgICAgICAgICBiZWZvcmVTZW5kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuICQuYWpheChvcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgZ2V0OmZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdHRVQnLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuICAgICAgICBzcGxpdEdldDogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIH0sXG4gICAgICAgIHBvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncG9zdCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgcGF0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncGF0Y2gnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHB1dDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwdXQnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKHBhcmFtcywgYWpheE9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vREVMRVRFIGRvZXNuJ3Qgc3VwcG9ydCBib2R5IHBhcmFtcywgYnV0IGpRdWVyeSB0aGlua3MgaXQgZG9lcy5cbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRyYW5zcG9ydE9wdGlvbnMsIGFqYXhPcHRpb25zKTtcbiAgICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1ldGVyUGFyc2VyKHJlc3VsdChwYXJhbXMpKTtcbiAgICAgICAgICAgIGlmICgkLnRyaW0ocGFyYW1zKSkge1xuICAgICAgICAgICAgICAgIHZhciBkZWxpbWl0ZXIgPSAocmVzdWx0KG9wdGlvbnMudXJsKS5pbmRleE9mKCc/JykgPT09IC0xKSA/ICc/JyA6ICcmJztcbiAgICAgICAgICAgICAgICBvcHRpb25zLnVybCA9IHJlc3VsdChvcHRpb25zLnVybCkgKyBkZWxpbWl0ZXIgKyBwYXJhbXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdERUxFVEUnLCBudWxsLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgaGVhZDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydoZWFkJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBvcHRpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ29wdGlvbnMnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHRyYW5zcG9ydCA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9ub2RlLWh0dHAtdHJhbnNwb3J0JykgOiByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbnZhciB0cmFuc3BvcnQgPSByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbm1vZHVsZS5leHBvcnRzID0gdHJhbnNwb3J0O1xuIiwiLyoqXG4vKiBJbmhlcml0IGZyb20gYSBjbGFzcyAodXNpbmcgcHJvdG90eXBlIGJvcnJvd2luZylcbiovXG4ndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIGluaGVyaXQoQywgUCkge1xuICAgIHZhciBGID0gZnVuY3Rpb24gKCkge307XG4gICAgRi5wcm90b3R5cGUgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZSA9IG5ldyBGKCk7XG4gICAgQy5fX3N1cGVyID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDO1xufVxuXG4vKipcbiogU2hhbGxvdyBjb3B5IG9mIGFuIG9iamVjdFxuKi9cbnZhciBleHRlbmQgPSBmdW5jdGlvbiAoZGVzdCAvKiwgdmFyX2FyZ3MqLykge1xuICAgIHZhciBvYmogPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHZhciBjdXJyZW50O1xuICAgIGZvciAodmFyIGogPSAwOyBqPG9iai5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAoIShjdXJyZW50ID0gb2JqW2pdKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkbyBub3Qgd3JhcCBpbm5lciBpbiBkZXN0Lmhhc093blByb3BlcnR5IG9yIGJhZCB0aGluZ3Mgd2lsbCBoYXBwZW5cbiAgICAgICAgLypqc2hpbnQgLVcwODkgKi9cbiAgICAgICAgZm9yICh2YXIga2V5IGluIGN1cnJlbnQpIHtcbiAgICAgICAgICAgIGRlc3Rba2V5XSA9IGN1cnJlbnRba2V5XTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkZXN0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYmFzZSwgcHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgdmFyIHBhcmVudCA9IGJhc2U7XG4gICAgdmFyIGNoaWxkO1xuXG4gICAgY2hpbGQgPSBwcm9wcyAmJiBwcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSA/IHByb3BzLmNvbnN0cnVjdG9yIDogZnVuY3Rpb24gKCkgeyByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IH07XG5cbiAgICAvLyBhZGQgc3RhdGljIHByb3BlcnRpZXMgdG8gdGhlIGNoaWxkIGNvbnN0cnVjdG9yIGZ1bmN0aW9uXG4gICAgZXh0ZW5kKGNoaWxkLCBwYXJlbnQsIHN0YXRpY1Byb3BzKTtcblxuICAgIC8vIGFzc29jaWF0ZSBwcm90b3R5cGUgY2hhaW5cbiAgICBpbmhlcml0KGNoaWxkLCBwYXJlbnQpO1xuXG4gICAgLy8gYWRkIGluc3RhbmNlIHByb3BlcnRpZXNcbiAgICBpZiAocHJvcHMpIHtcbiAgICAgICAgZXh0ZW5kKGNoaWxkLnByb3RvdHlwZSwgcHJvcHMpO1xuICAgIH1cblxuICAgIC8vIGRvbmVcbiAgICByZXR1cm4gY2hpbGQ7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLypqc2hpbnQgbG9vcGZ1bmM6ZmFsc2UgKi9cblxuZnVuY3Rpb24gX3codmFsKSB7XG4gICAgaWYgKHZhbCAmJiB2YWwudGhlbikge1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgIH1cbiAgICB2YXIgcCA9ICQuRGVmZXJyZWQoKTtcbiAgICBwLnJlc29sdmUodmFsKTtcblxuICAgIHJldHVybiBwLnByb21pc2UoKTtcbn1cblxuZnVuY3Rpb24gc2VxKCkge1xuICAgIHZhciBsaXN0ID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmFwcGx5KGFyZ3VtZW50cyk7XG5cbiAgICBmdW5jdGlvbiBuZXh0KHApIHtcbiAgICAgICAgdmFyIGN1ciA9IGxpc3Quc3BsaWNlKDAsMSlbMF07XG5cbiAgICAgICAgaWYgKCFjdXIpIHtcbiAgICAgICAgICAgIHJldHVybiBwO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF93KGN1cihwKSkudGhlbihuZXh0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gKHNlZWQpIHtcbiAgICAgICAgcmV0dXJuIG5leHQoc2VlZCkuZmFpbChzZXEuZmFpbCk7XG4gICAgfTtcbn1cblxuZnVuY3Rpb24gTWFrZVNlcShvYmopIHtcbiAgICB2YXIgcmVzID0ge1xuICAgICAgICBfX2NhbGxzOiBbXSxcblxuICAgICAgICBvcmlnaW5hbDogb2JqLFxuXG4gICAgICAgIHRoZW46IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goZm4pO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIC8vIGNsZWFuIHVwXG4gICAgICAgICAgICB0aGlzLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIF90aGlzLl9fY2FsbHMubGVuZ3RoID0gMDtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBzZXEuYXBwbHkobnVsbCwgdGhpcy5fX2NhbGxzKSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGZhaWw6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgc2VxLmZhaWwgPSBmbjtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBmdW5jTWFrZXIgPSBmdW5jdGlvbiAocCwgb2JqKSB7XG4gICAgICAgIHZhciBmbiA9IG9ialtwXS5iaW5kKG9iaik7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goRnVuY3Rpb24uYmluZC5hcHBseShmbiwgW251bGxdLmNvbmNhdChhcmdzKSkpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH07XG4gICAgfTtcblxuICAgIGZvciAodmFyIHByb3AgaW4gb2JqKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygb2JqW3Byb3BdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXNbcHJvcF0gPSBmdW5jTWFrZXIocHJvcCwgb2JqKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlc1twcm9wXSA9IG9ialtwcm9wXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gTWFrZVNlcTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgX3BpY2s6IGZ1bmN0aW9uIChvYmosIHByb3BzKSB7XG4gICAgICAgIHZhciByZXMgPSB7fTtcbiAgICAgICAgZm9yICh2YXIgcCBpbiBvYmopIHtcbiAgICAgICAgICAgIGlmIChwcm9wcy5pbmRleE9mKHApICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIHJlc1twXSA9IG9ialtwXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxufTtcbiIsIi8qKlxuICogVXRpbGl0aWVzIGZvciB3b3JraW5nIHdpdGggcXVlcnkgc3RyaW5nc1xuKi9cbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSAoZnVuY3Rpb24gKCkge1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHRvIG1hdHJpeCBmb3JtYXRcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBxcyBPYmplY3QgdG8gY29udmVydCB0byBxdWVyeSBzdHJpbmdcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ30gICAgTWF0cml4LWZvcm1hdCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuICAgICAgICB0b01hdHJpeEZvcm1hdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCB8fCBxcyA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJzsnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgdmFyIE9QRVJBVE9SUyA9IFsnPCcsICc+JywgJyEnXTtcbiAgICAgICAgICAgICQuZWFjaChxcywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnc3RyaW5nJyB8fCAkLmluQXJyYXkoJC50cmltKHZhbHVlKS5jaGFyQXQoMCksIE9QRVJBVE9SUykgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gJz0nICsgdmFsdWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciBtdHJ4ID0gJzsnICsgcmV0dXJuQXJyYXkuam9pbignOycpO1xuICAgICAgICAgICAgcmV0dXJuIG10cng7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHN0cmluZ3MvYXJyYXlzL29iamVjdHMgdG8gdHlwZSAnYT1iJmI9YydcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b1F1ZXJ5Rm9ybWF0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgJC5lYWNoKHFzLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmICgkLmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUuam9pbignLCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICAvL01vc3RseSBmb3IgZGF0YSBhcGlcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBKU09OLnN0cmluZ2lmeSh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgJz0nICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciByZXN1bHQgPSByZXR1cm5BcnJheS5qb2luKCcmJyk7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyBzdHJpbmdzIG9mIHR5cGUgJ2E9YiZiPWMnIHRvIHsgYTpiLCBiOmN9XG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHFzXG4gICAgICAgICAqIEByZXR1cm4ge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHFzVG9PYmplY3Q6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQgfHwgcXMgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcXNBcnJheSA9IHFzLnNwbGl0KCcmJyk7XG4gICAgICAgICAgICB2YXIgcmV0dXJuT2JqID0ge307XG4gICAgICAgICAgICAkLmVhY2gocXNBcnJheSwgZnVuY3Rpb24gKGluZGV4LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBxS2V5ID0gdmFsdWUuc3BsaXQoJz0nKVswXTtcbiAgICAgICAgICAgICAgICB2YXIgcVZhbCA9IHZhbHVlLnNwbGl0KCc9JylbMV07XG5cbiAgICAgICAgICAgICAgICBpZiAocVZhbC5pbmRleE9mKCcsJykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHFWYWwgPSBxVmFsLnNwbGl0KCcsJyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuT2JqW3FLZXldID0gcVZhbDtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuT2JqO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOb3JtYWxpemVzIGFuZCBtZXJnZXMgc3RyaW5ncyBvZiB0eXBlICdhPWInLCB7IGI6Y30gdG8geyBhOmIsIGI6Y31cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzMVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXMyXG4gICAgICAgICAqIEByZXR1cm4ge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIG1lcmdlUVM6IGZ1bmN0aW9uIChxczEsIHFzMikge1xuICAgICAgICAgICAgdmFyIG9iajEgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMSkpO1xuICAgICAgICAgICAgdmFyIG9iajIgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMikpO1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHt9LCBvYmoxLCBvYmoyKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhZGRUcmFpbGluZ1NsYXNoOiBmdW5jdGlvbiAodXJsKSB7XG4gICAgICAgICAgICBpZiAoIXVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAodXJsLmNoYXJBdCh1cmwubGVuZ3RoIC0gMSkgPT09ICcvJykgPyB1cmwgOiAodXJsICsgJy8nKTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuXG5cblxuIiwiLyoqXG4gKiBVdGlsaXRpZXMgZm9yIHdvcmtpbmcgd2l0aCB0aGUgcnVuIHNlcnZpY2VcbiovXG4ndXNlIHN0cmljdCc7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuL3F1ZXJ5LXV0aWwnKTtcbnZhciBNQVhfVVJMX0xFTkdUSCA9IDIwNDg7XG5cbm1vZHVsZS5leHBvcnRzID0gKGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICAvKipcbiAgICAgICAgICogcmV0dXJucyBvcGVyYXRpb25zIG9mIHRoZSBmb3JtIGBbW29wMSxvcDJdLCBbYXJnMSwgYXJnMl1dYFxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R8QXJyYXl8U3RyaW5nfSBgb3BlcmF0aW9uc2Agb3BlcmF0aW9ucyB0byBwZXJmb3JtXG4gICAgICAgICAqIEBwYXJhbSAge0FycmF5fSBgYXJnc2AgYXJndW1lbnRzIGZvciBvcGVyYXRpb25cbiAgICAgICAgICogQHJldHVybiB7U3RyaW5nfSAgICBNYXRyaXgtZm9ybWF0IHF1ZXJ5IHBhcmFtZXRlcnNcbiAgICAgICAgICovXG4gICAgICAgIG5vcm1hbGl6ZU9wZXJhdGlvbnM6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBhcmdzKSB7XG4gICAgICAgICAgICBpZiAoIWFyZ3MpIHtcbiAgICAgICAgICAgICAgICBhcmdzID0gW107XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgcmV0dXJuTGlzdCA9IHtcbiAgICAgICAgICAgICAgICBvcHM6IFtdLFxuICAgICAgICAgICAgICAgIGFyZ3M6IFtdXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX2NvbmNhdCA9IGZ1bmN0aW9uIChhcnIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKGFyciAhPT0gbnVsbCAmJiBhcnIgIT09IHVuZGVmaW5lZCkgPyBbXS5jb25jYXQoYXJyKSA6IFtdO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgLy97IGFkZDogWzEsMl0sIHN1YnRyYWN0OiBbMiw0XSB9XG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZVBsYWluT2JqZWN0cyA9IGZ1bmN0aW9uIChvcGVyYXRpb25zLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICQuZWFjaChvcGVyYXRpb25zLCBmdW5jdGlvbiAob3BuLCBhcmcpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcG4pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KGFyZykpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIC8veyBuYW1lOiAnYWRkJywgcGFyYW1zOiBbMV0gfVxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVTdHJ1Y3R1cmVkT2JqZWN0cyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcGVyYXRpb24ubmFtZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChvcGVyYXRpb24ucGFyYW1zKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZU9iamVjdCA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKChvcGVyYXRpb24ubmFtZSkgPyBfbm9ybWFsaXplU3RydWN0dXJlZE9iamVjdHMgOiBfbm9ybWFsaXplUGxhaW5PYmplY3RzKShvcGVyYXRpb24sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVMaXRlcmFscyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIGFyZ3MsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcGVyYXRpb24pO1xuICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQoYXJncykpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZUFycmF5cyA9IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBhcmcsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJC5lYWNoKG9wZXJhdGlvbnMsIGZ1bmN0aW9uIChpbmRleCwgb3BuKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qob3BuKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgX25vcm1hbGl6ZU9iamVjdChvcG4sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgX25vcm1hbGl6ZUxpdGVyYWxzKG9wbiwgYXJnc1tpbmRleF0sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KG9wZXJhdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZU9iamVjdChvcGVyYXRpb25zLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoJC5pc0FycmF5KG9wZXJhdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZUFycmF5cyhvcGVyYXRpb25zLCBhcmdzLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZUxpdGVyYWxzKG9wZXJhdGlvbnMsIGFyZ3MsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgfSxcblxuICAgICAgICBzcGxpdEdldEZhY3Rvcnk6IGZ1bmN0aW9uIChodHRwT3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICB2YXIgaHR0cCA9IHRoaXM7XG4gICAgICAgICAgICAgICAgdmFyIGdldFZhbHVlID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhbHVlID0gb3B0aW9uc1tuYW1lXSB8fCBodHRwT3B0aW9uc1tuYW1lXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciBnZXRGaW5hbFVybCA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybCA9IGdldFZhbHVlKCd1cmwnLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRhdGEgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZXJlIGlzIGVhc3kgKG9yIGtub3duKSB3YXkgdG8gZ2V0IHRoZSBmaW5hbCBVUkwganF1ZXJ5IGlzIGdvaW5nIHRvIHNlbmQgc29cbiAgICAgICAgICAgICAgICAgICAgLy8gd2UncmUgcmVwbGljYXRpbmcgaXQuIFRoZSBwcm9jZXNzIG1pZ2h0IGNoYW5nZSBhdCBzb21lIHBvaW50IGJ1dCBpdCBwcm9iYWJseSB3aWxsIG5vdC5cbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gUmVtb3ZlIGhhc2hcbiAgICAgICAgICAgICAgICAgICAgdXJsID0gdXJsLnJlcGxhY2UoLyMuKiQvLCAnJyk7XG4gICAgICAgICAgICAgICAgICAgIC8vIDEuIEFwcGVuZCBxdWVyeSBzdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXJ5UGFyYW1zID0gcXV0aWwudG9RdWVyeUZvcm1hdChkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXN0aW9uSWR4ID0gdXJsLmluZGV4T2YoJz8nKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHF1ZXJ5UGFyYW1zICYmIHF1ZXN0aW9uSWR4ID4gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmwgKyAnJicgKyBxdWVyeVBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChxdWVyeVBhcmFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybCArICc/JyArIHF1ZXJ5UGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmw7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgdXJsID0gZ2V0RmluYWxVcmwocGFyYW1zKTtcbiAgICAgICAgICAgICAgICAvLyBXZSBtdXN0IHNwbGl0IHRoZSBHRVQgaW4gbXVsdGlwbGUgc2hvcnQgVVJMJ3NcbiAgICAgICAgICAgICAgICAvLyBUaGUgb25seSBwcm9wZXJ0eSBhbGxvd2VkIHRvIGJlIHNwbGl0IGlzIFwiaW5jbHVkZVwiXG4gICAgICAgICAgICAgICAgaWYgKHBhcmFtcyAmJiBwYXJhbXMuaW5jbHVkZSAmJiB1cmwubGVuZ3RoID4gTUFYX1VSTF9MRU5HVEgpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmFtc0NvcHkgPSAkLmV4dGVuZCh0cnVlLCB7fSwgcGFyYW1zKTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHBhcmFtc0NvcHkuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybE5vSW5jbHVkZXMgPSBnZXRGaW5hbFVybChwYXJhbXNDb3B5KTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRpZmYgPSBNQVhfVVJMX0xFTkdUSCAtIHVybE5vSW5jbHVkZXMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IG9wdGlvbnMuc3VjY2VzcyB8fCBodHRwT3B0aW9ucy5zdWNjZXNzIHx8ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZEVycm9yID0gb3B0aW9ucy5lcnJvciB8fCBodHRwT3B0aW9ucy5lcnJvciB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSB0aGUgb3JpZ2luYWwgc3VjY2VzcyBhbmQgZXJyb3IgY2FsbGJhY2tzXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuc3VjY2VzcyA9ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvciA9ICQubm9vcDtcblxuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZSA9IHBhcmFtcy5pbmNsdWRlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VyckluY2x1ZGVzID0gW107XG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmNsdWRlT3B0cyA9IFtjdXJySW5jbHVkZXNdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHZhcmlhYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgYSBncmVlZHkgYXBwcm9hY2ggZm9yIG5vdywgY2FuIGJlIG9wdGltaXplZCB0byBiZSBzb2x2ZWQgaW4gYSBtb3JlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBlZmZpY2llbnQgd2F5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyArIDEgaXMgdGhlIGNvbW1hXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3Vyckxlbmd0aCArIHZhcmlhYmxlLmxlbmd0aCArIDEgPCBkaWZmKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzLnB1c2godmFyaWFibGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJMZW5ndGggKz0gdmFyaWFibGUubGVuZ3RoICsgMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzID0gW3ZhcmlhYmxlXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlT3B0cy5wdXNoKGN1cnJJbmNsdWRlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aCArIHZhcmlhYmxlLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB2YXIgcmVxcyA9ICQubWFwKGluY2x1ZGVPcHRzLCBmdW5jdGlvbiAoaW5jbHVkZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlcVBhcmFtcyA9ICQuZXh0ZW5kKHt9LCBwYXJhbXMsIHsgaW5jbHVkZTogaW5jbHVkZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChyZXFQYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgJC53aGVuLmFwcGx5KCQsIHJlcXMpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRWFjaCBhcmd1bWVudCBhcmUgYXJyYXlzIG9mIHRoZSBhcmd1bWVudHMgb2YgZWFjaCBkb25lIHJlcXVlc3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgZmlyc3QgYXJyYXkgb2YgYXJndW1lbnRzIGlzIHRoZSBkYXRhXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNWYWxpZCA9IGFyZ3VtZW50c1swXSAmJiBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaG91bGQgbmV2ZXIgaGFwcGVuLi4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpcnN0UmVzcG9uc2UgPSBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNSdW5BUEkgPSAoaXNPYmplY3QgJiYgJC5pc1BsYWluT2JqZWN0KGZpcnN0UmVzcG9uc2UudmFyaWFibGVzKSkgfHwgIWlzT2JqZWN0O1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzUnVuQVBJKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzT2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnZ3JlZ2F0ZSB0aGUgdmFyaWFibGVzIHByb3BlcnR5IG9ubHlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZVJ1biA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJ1biA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVSdW4udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZVJ1biwgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFycmF5IG9mIHJ1bnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWdyZWdhdGUgdmFyaWFibGVzIGluIGVhY2ggcnVuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkUnVucyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVucyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISQuaXNBcnJheShydW5zKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChydW5zLCBmdW5jdGlvbiAoaWR4UnVuLCBydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocnVuLmlkICYmICFhZ2dyZWdhdGVkUnVuc1tydW4uaWRdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bi52YXJpYWJsZXMgPSBydW4udmFyaWFibGVzIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVuc1tydW4uaWRdID0gcnVuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocnVuLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHR1cm4gaXQgaW50byBhbiBhcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVucyA9ICQubWFwKGFnZ3JlZ2F0ZWRSdW5zLCBmdW5jdGlvbiAocnVuKSB7IHJldHVybiBydW47IH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyB2YXJpYWJsZXMgQVBJXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSByZXNwb25zZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkVmFyaWFibGVzID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFycyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIHZhcnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IuYXBwbHkoaHR0cCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZWplY3QuYXBwbHkoZHRkLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuIl19 diff --git a/dist/epicenter.min.js b/dist/epicenter.min.js index b4488f28..190b7748 100644 --- a/dist/epicenter.min.js +++ b/dist/epicenter.min.js @@ -17,7 +17,7 @@ var F={util:{},factory:{},transport:{},store:{},service:{},manager:{strategy:{}} }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./api-version.json":5,"./managers/auth-manager":7,"./managers/epicenter-channel-manager":9,"./managers/run-manager":11,"./managers/run-strategies/always-new-strategy":12,"./managers/run-strategies/conditional-creation-strategy":13,"./managers/run-strategies/identity-strategy":14,"./managers/run-strategies/new-if-initialized-strategy":16,"./managers/run-strategies/new-if-missing-strategy":17,"./managers/run-strategies/new-if-persisted-strategy":18,"./managers/scenario-manager":21,"./managers/world-manager":23,"./service/admin-file-service":24,"./service/asset-api-adapter":25,"./service/auth-api-service":26,"./service/channel-service":27,"./service/configuration-service":28,"./service/data-api-service":29,"./service/member-api-adapter":30,"./service/run-api-service":31,"./service/state-api-adapter":32,"./service/url-config-service":33,"./service/user-api-adapter":34,"./service/variables-api-service":35,"./service/world-api-adapter":36,"./store/cookie-store":37,"./store/store-factory":38,"./transport/ajax-http-transport":39,"./transport/http-transport-factory":40,"./util/inherit":41,"./util/make-sequence":42,"./util/query-util":44,"./util/run-util":45}],7:[function(require,module,exports){ -"use strict";function saveSession(userInfo,store){var serialized=JSON.stringify(userInfo);store.set(EPI_SESSION_KEY,serialized),store.set(EPI_COOKIE_KEY,userInfo.auth_token)}function getSession(store){var session=store.get(EPI_SESSION_KEY)||"{}";return JSON.parse(session)}function AuthManager(options){this.options=$.extend(!0,{},defaults,options);var urlConfig=new ConfigService(this.options).get("server");this.options.account||(this.options.account=urlConfig.accountPath),void 0===this.options.project&&(this.options.project=urlConfig.projectPath),this.store=new StorageFactory(this.options.store),session=getSession(this.store),token=this.store.get(EPI_COOKIE_KEY)||"",this.authAdapter=new AuthAdapter(this.options,{token:session.auth_token})}var ConfigService=require("../service/configuration-service");var AuthAdapter=require("../service/auth-api-service");var MemberAdapter=require("../service/member-api-adapter");var StorageFactory=require("../store/store-factory");var Buffer=require("buffer").Buffer;var keyNames=require("./key-names");var defaults={store:{synchronous:!0}};var EPI_COOKIE_KEY=keyNames.EPI_COOKIE_KEY;var EPI_SESSION_KEY=keyNames.EPI_SESSION_KEY;var store;var token;var session;var _findUserInGroup=function(members,id){for(var j=0;j1&&groupId){var filteredGroups=$.grep(memberInfo,function(resGroup){return resGroup.groupId===groupId});group=1===filteredGroups.length?filteredGroups[0]:null}if(group){var groupSelection=group.groupId;data.groupSelection[adapterOptions.project]=groupSelection;var sessionInfoWithGroup=$.extend({},sessionInfo,{groupId:group.groupId,groupName:group.name,isFac:"facilitator"===_findUserInGroup(group.members,userInfo.user_id).role});saveSession(sessionInfoWithGroup,_this.store),outSuccess.apply(this,[data]),$d.resolve(data)}else handleGroupError("This user is associated with more than one group. Please specify a group id to log into and try again",403,data)}).fail($d.reject)};return adapterOptions.success=handleSuccess,adapterOptions.error=function(response){return adapterOptions.account?(adapterOptions.account=null,adapterOptions.error=function(){outError.apply(this,arguments),$d.reject(response)},void _this.authAdapter.login(adapterOptions)):(outError.apply(this,arguments),void $d.reject(response))},this.authAdapter.login(adapterOptions),$d.promise()},logout:function(options){var adapterOptions=$.extend(!0,{token:token},this.options,options);var removeCookieFn=function(response){store.remove(EPI_COOKIE_KEY,adapterOptions),store.remove(EPI_SESSION_KEY,adapterOptions),token=""};return this.authAdapter.logout(adapterOptions).done(removeCookieFn)},getToken:function(options){var httpOptions=$.extend(!0,this.options,options);var $d=$.Deferred();return token?$d.resolve(token):this.login(httpOptions).then($d.resolve),$d.promise()},getUserGroups:function(params,options){var adapterOptions=$.extend(!0,{success:$.noop},this.options,options);var $d=$.Deferred();var outSuccess=adapterOptions.success;adapterOptions.success=function(memberInfo){adapterOptions.project&&(memberInfo=$.grep(memberInfo,function(group){return group.project===adapterOptions.project})),outSuccess.apply(this,[memberInfo]),$d.resolve(memberInfo)};var memberAdapter=new MemberAdapter({token:params.token});return memberAdapter.getGroupsForUser(params,adapterOptions).fail($d.reject),$d.promise()},getCurrentUserSessionInfo:function(options){return getSession(this.store,options)}}),module.exports=AuthManager; +"use strict";function saveSession(userInfo,store){var serialized=JSON.stringify(userInfo);store.set(EPI_SESSION_KEY,serialized),store.set(EPI_COOKIE_KEY,userInfo.auth_token)}function getSession(store){var session=store.get(EPI_SESSION_KEY)||"{}";return JSON.parse(session)}function AuthManager(options){this.options=$.extend(!0,{},defaults,options);var urlConfig=new ConfigService(this.options).get("server");this.isLocal=urlConfig.isLocalhost(),this.options.account||(this.options.account=urlConfig.accountPath),void 0===this.options.project&&(this.options.project=urlConfig.projectPath),this.store=new StorageFactory(this.options.store),session=getSession(this.store),token=this.store.get(EPI_COOKIE_KEY)||"",this.authAdapter=new AuthAdapter(this.options,{token:session.auth_token})}var ConfigService=require("../service/configuration-service");var AuthAdapter=require("../service/auth-api-service");var MemberAdapter=require("../service/member-api-adapter");var StorageFactory=require("../store/store-factory");var Buffer=require("buffer").Buffer;var keyNames=require("./key-names");var defaults={store:{synchronous:!0}};var EPI_COOKIE_KEY=keyNames.EPI_COOKIE_KEY;var EPI_SESSION_KEY=keyNames.EPI_SESSION_KEY;var store;var token;var session;var _findUserInGroup=function(members,id){for(var j=0;j1&&groupId){var filteredGroups=$.grep(memberInfo,function(resGroup){return resGroup.groupId===groupId});group=1===filteredGroups.length?filteredGroups[0]:null}if(group){var groupSelection=group.groupId;data.groupSelection[adapterOptions.project]=groupSelection;var sessionInfoWithGroup=$.extend({},sessionInfo,{groupId:group.groupId,groupName:group.name,isFac:"facilitator"===_findUserInGroup(group.members,userInfo.user_id).role});saveSession(sessionInfoWithGroup,_this.store),outSuccess.apply(this,[data]),$d.resolve(data)}else handleGroupError("This user is associated with more than one group. Please specify a group id to log into and try again",403,data)}).fail($d.reject)};return adapterOptions.success=handleSuccess,adapterOptions.error=function(response){return adapterOptions.account?(adapterOptions.account=null,adapterOptions.error=function(){outError.apply(this,arguments),$d.reject(response)},void _this.authAdapter.login(adapterOptions)):(outError.apply(this,arguments),void $d.reject(response))},this.authAdapter.login(adapterOptions),$d.promise()},logout:function(options){var adapterOptions=$.extend(!0,{token:token},this.options,options);var removeCookieFn=function(response){store.remove(EPI_COOKIE_KEY,adapterOptions),store.remove(EPI_SESSION_KEY,adapterOptions),token=""};return this.authAdapter.logout(adapterOptions).done(removeCookieFn)},getToken:function(options){var httpOptions=$.extend(!0,this.options,options);var $d=$.Deferred();return token?$d.resolve(token):this.login(httpOptions).then($d.resolve),$d.promise()},getUserGroups:function(params,options){var adapterOptions=$.extend(!0,{success:$.noop},this.options,options);var $d=$.Deferred();var outSuccess=adapterOptions.success;adapterOptions.success=function(memberInfo){adapterOptions.project&&(memberInfo=$.grep(memberInfo,function(group){return group.project===adapterOptions.project})),outSuccess.apply(this,[memberInfo]),$d.resolve(memberInfo)};var memberAdapter=new MemberAdapter({token:params.token});return memberAdapter.getGroupsForUser(params,adapterOptions).fail($d.reject),$d.promise()},getCurrentUserSessionInfo:function(options){return getSession(this.store,options)}}),module.exports=AuthManager; },{"../service/auth-api-service":26,"../service/configuration-service":28,"../service/member-api-adapter":30,"../store/store-factory":38,"./key-names":10,"buffer":1}],8:[function(require,module,exports){ "use strict";var Channel=require("../service/channel-service");var ChannelManager=function(options){if(!$.cometd)throw new Error("Cometd library not found. Please include epicenter-multiplayer-dependencies.js");if(!options||!options.url)throw new Error("Please provide an url for the cometd server");var defaults={url:"",logLevel:"info",websocketEnabled:!1,shareConnection:!1,channel:{}};var defaultCometOptions=$.extend(!0,{},defaults,options);if(this.currentSubscriptions=[],this.options=defaultCometOptions,defaultCometOptions.shareConnection&&ChannelManager.prototype._cometd)return this.cometd=ChannelManager.prototype._cometd,this;var cometd=new $.Cometd;ChannelManager.prototype._cometd=cometd,cometd.websocketEnabled=defaultCometOptions.websocketEnabled,this.isConnected=!1;var connectionBroken=function(message){$(this).trigger("disconnect",message)};var connectionSucceeded=function(message){$(this).trigger("connect",message)};var me=this;cometd.configure(defaultCometOptions),cometd.addListener("/meta/connect",function(message){var wasConnected=this.isConnected;this.isConnected=message.successful===!0,!wasConnected&&this.isConnected?connectionSucceeded.call(this,message):wasConnected&&!this.isConnected&&connectionBroken.call(this,message)}.bind(this)),cometd.addListener("/meta/disconnect",connectionBroken),cometd.addListener("/meta/handshake",function(message){message.successful&&cometd.batch(function(){$(me.currentSubscriptions).each(function(index,subs){cometd.resubscribe(subs)})})}),cometd.addListener("/meta/subscribe",function(message){$(me).trigger("subscribe",message)}),cometd.addListener("/meta/unsubscribe",function(message){$(me).trigger("unsubscribe",message)}),cometd.addListener("/meta/publish",function(message){$(me).trigger("publish",message)}),cometd.addListener("/meta/unsuccessful",function(message){$(me).trigger("error",message)}),cometd.handshake(),this.cometd=cometd};ChannelManager.prototype=$.extend(ChannelManager.prototype,{getChannel:function(options){options&&!$.isPlainObject(options)&&(options={base:options});var defaults={transport:this.cometd};var channel=new Channel($.extend(!0,{},this.options.channel,defaults,options));var subs=channel.subscribe;channel.subscribe=function(){var subid=subs.apply(channel,arguments);return this.currentSubscriptions=this.currentSubscriptions.concat(subid),subid}.bind(this);var unsubs=channel.unsubscribe;return channel.unsubscribe=function(){var removed=unsubs.apply(channel,arguments);for(var i=0;i\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && url.length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = '?include='.length;\n var variable = include.pop();\n while (variable) {\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + variable.length + 1 < diff) {\n currIncludes.push(variable);\n currLength += variable.length + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + variable.length;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ##File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n // config || (config = configService.get());\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || store.get('epicenter.token') || '',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: '',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {String} `folderType` One of Model|Static|Node\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, folderType, options) {\n var path = folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ##Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * ##Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: '',\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n domain: 'forio.com',\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ##Authentication API Service\n *\n * The Authentication API Service provides methods for logging in and logging out. On login, this service creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n * auth.logout();\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n /**\n * Logs user out from specified accounts.\n * Epicenter logout is not implemented yet, added a dummy promise that gets automatically resolved.\n *\n * **Example**\n *\n * auth.logout();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ##World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n $.extend(params, _pick(serviceOptions, ['account', 'project', 'group']));\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ##State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ##User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ##Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: '',\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar keyNames = require('../managers/key-names');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n var session = JSON.parse(store.get(keyNames.EPI_SESSION_KEY) || '{}');\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get(keyNames.EPI_COOKIE_KEY) || '',\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: session.userId,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n var serviceOptions = $.extend(true, {}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.forio.com'\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n\n document.cookie = encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookieReg = new RegExp('(?:(?:^|.*;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$');\n var val = document.cookie.replace(cookieReg, '$1');\n val = decodeURIComponent(val) || null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n\n document.cookie = encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var aKeys = document.cookie.replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* ####Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar ConfigService = require('../service/configuration-service');\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar StorageFactory = require('../store/store-factory');\nvar Buffer = require('buffer').Buffer;\nvar keyNames = require('./key-names');\n\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY;\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar store;\nvar token;\nvar session;\n\nfunction saveSession(userInfo, store) {\n var serialized = JSON.stringify(userInfo);\n store.set(EPI_SESSION_KEY, serialized);\n\n //jshint camelcase: false\n //jscs:disable\n store.set(EPI_COOKIE_KEY, userInfo.auth_token);\n}\n\nfunction getSession(store) {\n var session = store.get(EPI_SESSION_KEY) || '{}';\n return JSON.parse(session);\n}\n\nfunction AuthManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n var urlConfig = new ConfigService(this.options).get('server');\n if (!this.options.account) {\n this.options.account = urlConfig.accountPath;\n }\n\n // null might specified to disable project filtering\n if (this.options.project === undefined) {\n this.options.project = urlConfig.projectPath;\n }\n\n this.store = new StorageFactory(this.options.store);\n session = getSession(this.store);\n token = this.store.get(EPI_COOKIE_KEY) || '';\n //jshint camelcase: false\n //jscs:disable\n this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token });\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(memberInfo, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n var groupSelection = group.groupId;\n data.groupSelection[adapterOptions.project] = groupSelection;\n var sessionInfoWithGroup = $.extend({}, sessionInfo, {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n });\n saveSession(sessionInfoWithGroup, _this.store);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n }).fail($d.reject);\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var adapterOptions = $.extend(true, { token: token }, this.options, options);\n\n var removeCookieFn = function (response) {\n store.remove(EPI_COOKIE_KEY, adapterOptions);\n store.remove(EPI_SESSION_KEY, adapterOptions);\n token = '';\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = $.extend(true, this.options, options);\n\n var $d = $.Deferred();\n if (token) {\n $d.resolve(token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = $.extend(true, { success: $.noop }, this.options, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return getSession(this.store, options);\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `server` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `server.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `server.project` Epicenter project id.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\n\nvar AuthManager = require('./auth-manager');\n\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n var userInfo = session.getCurrentUserSessionInfo();\n\n var defaults = {\n account: userInfo.account,\n project: userInfo.project,\n };\n var defaultCometOptions = $.extend(true, {}, defaults, userInfo, options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getDataChannel('survey-responses');\n * gc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionStore = require('../../store/store-factory');\nvar classFrom = require('../../util/inherit');\nvar UrlService = require('../../service/url-config-service');\nvar AuthManager = require('../auth-manager');\n\nvar sessionStore = new SessionStore({});\nvar urlService = new UrlService();\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, path) {\n if (!path) {\n if (!urlService.isLocalhost()) {\n path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/');\n // make sure we don't get consecuteive '/' so we have a valid path for the session\n path = path.replace(/\\/{2,}/g,'/');\n } else {\n path = '';\n }\n }\n // set the seesionKey for the run\n sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path });\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.options.path);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession);\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","'use strict';\n\nmodule.exports = {\n EPI_COOKIE_KEY: 'epicenter.project.token',\n EPI_SESSION_KEY: 'epicenter.user.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","'use strict';\n\nvar Channel = require('../service/channel-service');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n }\n };\n var defaultCometOptions = $.extend(true, {}, defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake();\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('is-array')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\nBuffer.poolSize = 8192 // not used by this implementation\n\nvar rootParent = {}\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property\n * on objects.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\nfunction typedArraySupport () {\n function Bar () {}\n try {\n var arr = new Uint8Array(1)\n arr.foo = function () { return 42 }\n arr.constructor = Bar\n return arr.foo() === 42 && // typed array instances can be augmented\n arr.constructor === Bar && // constructor can be set\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\n/**\n * Class: Buffer\n * =============\n *\n * The Buffer constructor returns instances of `Uint8Array` that are augmented\n * with function properties for all the node `Buffer` API functions. We use\n * `Uint8Array` so that square bracket notation works as expected -- it returns\n * a single octet.\n *\n * By augmenting the instances, we can avoid modifying the `Uint8Array`\n * prototype.\n */\nfunction Buffer (arg) {\n if (!(this instanceof Buffer)) {\n // Avoid going through an ArgumentsAdaptorTrampoline in the common case.\n if (arguments.length > 1) return new Buffer(arg, arguments[1])\n return new Buffer(arg)\n }\n\n this.length = 0\n this.parent = undefined\n\n // Common case.\n if (typeof arg === 'number') {\n return fromNumber(this, arg)\n }\n\n // Slightly less common case.\n if (typeof arg === 'string') {\n return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')\n }\n\n // Unusual.\n return fromObject(this, arg)\n}\n\nfunction fromNumber (that, length) {\n that = allocate(that, length < 0 ? 0 : checked(length) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < length; i++) {\n that[i] = 0\n }\n }\n return that\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'\n\n // Assumption: byteLength() return value is always < kMaxLength.\n var length = byteLength(string, encoding) | 0\n that = allocate(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromObject (that, object) {\n if (Buffer.isBuffer(object)) return fromBuffer(that, object)\n\n if (isArray(object)) return fromArray(that, object)\n\n if (object == null) {\n throw new TypeError('must start with number, buffer, array or string')\n }\n\n if (typeof ArrayBuffer !== 'undefined') {\n if (object.buffer instanceof ArrayBuffer) {\n return fromTypedArray(that, object)\n }\n if (object instanceof ArrayBuffer) {\n return fromArrayBuffer(that, object)\n }\n }\n\n if (object.length) return fromArrayLike(that, object)\n\n return fromJsonObject(that, object)\n}\n\nfunction fromBuffer (that, buffer) {\n var length = checked(buffer.length) | 0\n that = allocate(that, length)\n buffer.copy(that, 0, 0, length)\n return that\n}\n\nfunction fromArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Duplicate of fromArray() to keep fromArray() monomorphic.\nfunction fromTypedArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n // Truncating the elements is probably not what people expect from typed\n // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior\n // of the old Buffer constructor.\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n array.byteLength\n that = Buffer._augment(new Uint8Array(array))\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromTypedArray(that, new Uint8Array(array))\n }\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.\n// Returns a zero-length buffer for inputs that don't conform to the spec.\nfunction fromJsonObject (that, object) {\n var array\n var length = 0\n\n if (object.type === 'Buffer' && isArray(object.data)) {\n array = object.data\n length = checked(array.length) | 0\n }\n that = allocate(that, length)\n\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n}\n\nfunction allocate (that, length) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = Buffer._augment(new Uint8Array(length))\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that.length = length\n that._isBuffer = true\n }\n\n var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1\n if (fromPool) that.parent = rootParent\n\n return that\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (subject, encoding) {\n if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)\n\n var buf = new Buffer(subject, encoding)\n delete buf.parent\n return buf\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n var i = 0\n var len = Math.min(x, y)\n while (i < len) {\n if (a[i] !== b[i]) break\n\n ++i\n }\n\n if (i !== len) {\n x = a[i]\n y = b[i]\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')\n\n if (list.length === 0) {\n return new Buffer(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; i++) {\n length += list[i].length\n }\n }\n\n var buf = new Buffer(length)\n var pos = 0\n for (i = 0; i < list.length; i++) {\n var item = list[i]\n item.copy(buf, pos)\n pos += item.length\n }\n return buf\n}\n\nfunction byteLength (string, encoding) {\n if (typeof string !== 'string') string = '' + string\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n // Deprecated\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\n// pre-set for values that may exist in the future\nBuffer.prototype.length = undefined\nBuffer.prototype.parent = undefined\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n start = start | 0\n end = end === undefined || end === Infinity ? this.length : end | 0\n\n if (!encoding) encoding = 'utf8'\n if (start < 0) start = 0\n if (end > this.length) end = this.length\n if (end <= start) return ''\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return 0\n return Buffer.compare(this, b)\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset) {\n if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff\n else if (byteOffset < -0x80000000) byteOffset = -0x80000000\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n if (val.length === 0) return -1 // special case: looking for empty string always fails\n return String.prototype.indexOf.call(this, val, byteOffset)\n }\n if (Buffer.isBuffer(val)) {\n return arrayIndexOf(this, val, byteOffset)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset)\n }\n\n function arrayIndexOf (arr, val, byteOffset) {\n var foundIndex = -1\n for (var i = 0; byteOffset + i < arr.length; i++) {\n if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex\n } else {\n foundIndex = -1\n }\n }\n return -1\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\n// `get` is deprecated\nBuffer.prototype.get = function get (offset) {\n console.log('.get() is deprecated. Access using array indexes instead.')\n return this.readUInt8(offset)\n}\n\n// `set` is deprecated\nBuffer.prototype.set = function set (v, offset) {\n console.log('.set() is deprecated. Access using array indexes instead.')\n return this.writeUInt8(v, offset)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; i++) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) throw new Error('Invalid hex string')\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n var swap = encoding\n encoding = offset\n offset = length | 0\n length = swap\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; i++) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = Buffer._augment(this.subarray(start, end))\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; i++) {\n newBuf[i] = this[i + start]\n }\n }\n\n if (newBuf.length) newBuf.parent = this.parent || this\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n if (offset < 0) throw new RangeError('index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; i--) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; i++) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n target._set(this.subarray(start, start + len), targetStart)\n }\n\n return len\n}\n\n// fill(value, start=0, end=buffer.length)\nBuffer.prototype.fill = function fill (value, start, end) {\n if (!value) value = 0\n if (!start) start = 0\n if (!end) end = this.length\n\n if (end < start) throw new RangeError('end < start')\n\n // Fill 0 bytes; we're done\n if (end === start) return\n if (this.length === 0) return\n\n if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')\n if (end < 0 || end > this.length) throw new RangeError('end out of bounds')\n\n var i\n if (typeof value === 'number') {\n for (i = start; i < end; i++) {\n this[i] = value\n }\n } else {\n var bytes = utf8ToBytes(value.toString())\n var len = bytes.length\n for (i = start; i < end; i++) {\n this[i] = bytes[i % len]\n }\n }\n\n return this\n}\n\n/**\n * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.\n * Added in Node 0.12. Only available in browsers that support ArrayBuffer.\n */\nBuffer.prototype.toArrayBuffer = function toArrayBuffer () {\n if (typeof Uint8Array !== 'undefined') {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n return (new Buffer(this)).buffer\n } else {\n var buf = new Uint8Array(this.length)\n for (var i = 0, len = buf.length; i < len; i += 1) {\n buf[i] = this[i]\n }\n return buf.buffer\n }\n } else {\n throw new TypeError('Buffer.toArrayBuffer not supported in this browser')\n }\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar BP = Buffer.prototype\n\n/**\n * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods\n */\nBuffer._augment = function _augment (arr) {\n arr.constructor = Buffer\n arr._isBuffer = true\n\n // save reference to original Uint8Array set method before overwriting\n arr._set = arr.set\n\n // deprecated\n arr.get = BP.get\n arr.set = BP.set\n\n arr.write = BP.write\n arr.toString = BP.toString\n arr.toLocaleString = BP.toString\n arr.toJSON = BP.toJSON\n arr.equals = BP.equals\n arr.compare = BP.compare\n arr.indexOf = BP.indexOf\n arr.copy = BP.copy\n arr.slice = BP.slice\n arr.readUIntLE = BP.readUIntLE\n arr.readUIntBE = BP.readUIntBE\n arr.readUInt8 = BP.readUInt8\n arr.readUInt16LE = BP.readUInt16LE\n arr.readUInt16BE = BP.readUInt16BE\n arr.readUInt32LE = BP.readUInt32LE\n arr.readUInt32BE = BP.readUInt32BE\n arr.readIntLE = BP.readIntLE\n arr.readIntBE = BP.readIntBE\n arr.readInt8 = BP.readInt8\n arr.readInt16LE = BP.readInt16LE\n arr.readInt16BE = BP.readInt16BE\n arr.readInt32LE = BP.readInt32LE\n arr.readInt32BE = BP.readInt32BE\n arr.readFloatLE = BP.readFloatLE\n arr.readFloatBE = BP.readFloatBE\n arr.readDoubleLE = BP.readDoubleLE\n arr.readDoubleBE = BP.readDoubleBE\n arr.writeUInt8 = BP.writeUInt8\n arr.writeUIntLE = BP.writeUIntLE\n arr.writeUIntBE = BP.writeUIntBE\n arr.writeUInt16LE = BP.writeUInt16LE\n arr.writeUInt16BE = BP.writeUInt16BE\n arr.writeUInt32LE = BP.writeUInt32LE\n arr.writeUInt32BE = BP.writeUInt32BE\n arr.writeIntLE = BP.writeIntLE\n arr.writeIntBE = BP.writeIntBE\n arr.writeInt8 = BP.writeInt8\n arr.writeInt16LE = BP.writeInt16LE\n arr.writeInt16BE = BP.writeInt16BE\n arr.writeInt32LE = BP.writeInt32LE\n arr.writeInt32BE = BP.writeInt32BE\n arr.writeFloatLE = BP.writeFloatLE\n arr.writeFloatBE = BP.writeFloatBE\n arr.writeDoubleLE = BP.writeDoubleLE\n arr.writeDoubleBE = BP.writeDoubleBE\n arr.fill = BP.fill\n arr.inspect = BP.inspect\n arr.toArrayBuffer = BP.toArrayBuffer\n\n return arr\n}\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; i++) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; i++) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n;(function (exports) {\n\t'use strict';\n\n var Arr = (typeof Uint8Array !== 'undefined')\n ? Uint8Array\n : Array\n\n\tvar PLUS = '+'.charCodeAt(0)\n\tvar SLASH = '/'.charCodeAt(0)\n\tvar NUMBER = '0'.charCodeAt(0)\n\tvar LOWER = 'a'.charCodeAt(0)\n\tvar UPPER = 'A'.charCodeAt(0)\n\tvar PLUS_URL_SAFE = '-'.charCodeAt(0)\n\tvar SLASH_URL_SAFE = '_'.charCodeAt(0)\n\n\tfunction decode (elt) {\n\t\tvar code = elt.charCodeAt(0)\n\t\tif (code === PLUS ||\n\t\t code === PLUS_URL_SAFE)\n\t\t\treturn 62 // '+'\n\t\tif (code === SLASH ||\n\t\t code === SLASH_URL_SAFE)\n\t\t\treturn 63 // '/'\n\t\tif (code < NUMBER)\n\t\t\treturn -1 //no match\n\t\tif (code < NUMBER + 10)\n\t\t\treturn code - NUMBER + 26 + 26\n\t\tif (code < UPPER + 26)\n\t\t\treturn code - UPPER\n\t\tif (code < LOWER + 26)\n\t\t\treturn code - LOWER + 26\n\t}\n\n\tfunction b64ToByteArray (b64) {\n\t\tvar i, j, l, tmp, placeHolders, arr\n\n\t\tif (b64.length % 4 > 0) {\n\t\t\tthrow new Error('Invalid string. Length must be a multiple of 4')\n\t\t}\n\n\t\t// the number of equal signs (place holders)\n\t\t// if there are two placeholders, than the two characters before it\n\t\t// represent one byte\n\t\t// if there is only one, then the three characters before it represent 2 bytes\n\t\t// this is just a cheap hack to not do indexOf twice\n\t\tvar len = b64.length\n\t\tplaceHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0\n\n\t\t// base64 is 4/3 + up to two characters of the original data\n\t\tarr = new Arr(b64.length * 3 / 4 - placeHolders)\n\n\t\t// if there are placeholders, only get up to the last complete 4 chars\n\t\tl = placeHolders > 0 ? b64.length - 4 : b64.length\n\n\t\tvar L = 0\n\n\t\tfunction push (v) {\n\t\t\tarr[L++] = v\n\t\t}\n\n\t\tfor (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))\n\t\t\tpush((tmp & 0xFF0000) >> 16)\n\t\t\tpush((tmp & 0xFF00) >> 8)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\tif (placeHolders === 2) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)\n\t\t\tpush(tmp & 0xFF)\n\t\t} else if (placeHolders === 1) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)\n\t\t\tpush((tmp >> 8) & 0xFF)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\treturn arr\n\t}\n\n\tfunction uint8ToBase64 (uint8) {\n\t\tvar i,\n\t\t\textraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes\n\t\t\toutput = \"\",\n\t\t\ttemp, length\n\n\t\tfunction encode (num) {\n\t\t\treturn lookup.charAt(num)\n\t\t}\n\n\t\tfunction tripletToBase64 (num) {\n\t\t\treturn encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)\n\t\t}\n\n\t\t// go through the array every three bytes, we'll deal with trailing stuff later\n\t\tfor (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n\t\t\ttemp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n\t\t\toutput += tripletToBase64(temp)\n\t\t}\n\n\t\t// pad the end with zeros, but make sure to not forget the extra bytes\n\t\tswitch (extraBytes) {\n\t\t\tcase 1:\n\t\t\t\ttemp = uint8[uint8.length - 1]\n\t\t\t\toutput += encode(temp >> 2)\n\t\t\t\toutput += encode((temp << 4) & 0x3F)\n\t\t\t\toutput += '=='\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\ttemp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])\n\t\t\t\toutput += encode(temp >> 10)\n\t\t\t\toutput += encode((temp >> 4) & 0x3F)\n\t\t\t\toutput += encode((temp << 2) & 0x3F)\n\t\t\t\toutput += '='\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn output\n\t}\n\n\texports.toByteArray = b64ToByteArray\n\texports.fromByteArray = uint8ToBase64\n}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))\n","\n/**\n * isArray\n */\n\nvar isArray = Array.isArray;\n\n/**\n * toString\n */\n\nvar str = Object.prototype.toString;\n\n/**\n * Whether or not the given `val`\n * is an array.\n *\n * example:\n *\n * isArray([]);\n * // > true\n * isArray(arguments);\n * // > false\n * isArray('');\n * // > false\n *\n * @param {mixed} val\n * @return {bool}\n */\n\nmodule.exports = isArray || function (val) {\n return !! val && '[object Array]' == str.call(val);\n};\n"]} \ No newline at end of file +{"version":3,"sources":["node_modules/grunt-browserify/node_modules/browserify/node_modules/browser-pack/_prelude.js","src/api-version.json","src/app.js","src/util/query-util.js","src/util/make-sequence.js","src/util/run-util.js","src/util/inherit.js","src/transport/http-transport-factory.js","src/transport/ajax-http-transport.js","src/service/url-config-service.js","src/service/configuration-service.js","src/service/run-api-service.js","src/service/admin-file-service.js","src/service/variables-api-service.js","src/service/data-api-service.js","src/service/auth-api-service.js","src/service/world-api-adapter.js","src/service/state-api-adapter.js","src/service/user-api-adapter.js","src/service/member-api-adapter.js","src/service/asset-api-adapter.js","src/store/cookie-store.js","src/store/store-factory.js","src/managers/scenario-manager.js","src/managers/run-manager.js","src/managers/auth-manager.js","src/managers/world-manager.js","src/managers/epicenter-channel-manager.js","src/service/channel-service.js","src/managers/run-strategies/always-new-strategy.js","src/managers/run-strategies/conditional-creation-strategy.js","src/managers/run-strategies/identity-strategy.js","src/managers/run-strategies/new-if-missing-strategy.js","src/managers/run-strategies/new-if-persisted-strategy.js","src/managers/run-strategies/new-if-initialized-strategy.js","src/util/object-util.js","src/managers/key-names.js","src/managers/special-operations.js","src/managers/channel-manager.js","src/managers/run-strategies/strategies-map.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/index.js","src/managers/run-strategies/multiplayer-strategy.js","src/managers/run-strategies/persistent-single-player-strategy.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/ieee754/index.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/base64-js/lib/b64.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/is-array/index.js"],"names":["F","util","factory","transport","store","service","manager","strategy","query","require","makeSequence","run","classFrom","Transport","Ajax","URL","Config","Run","File","Variables","Data","Auth","World","State","User","Member","Asset","Cookie","Store","ScenarioManager","RunManager","AuthManager","WorldManager","identity","ChannelManager","Channel","version","api","global","module","exports","toMatrixFormat","qs","undefined","String","returnArray","OPERATORS","$","each","key","value","inArray","trim","charAt","push","mtrx","join","toQueryFormat","isArray","isPlainObject","JSON","stringify","result","qsToObject","qsArray","split","returnObj","index","qKey","qVal","indexOf","mergeQS","qs1","qs2","obj1","this","obj2","extend","addTrailingSlash","url","length","_w","val","then","p","Deferred","resolve","promise","seq","next","cur","list","splice","Array","prototype","slice","apply","arguments","seed","fail","MakeSeq","obj","res","__calls","original","fn","start","_this","funcMaker","bind","args","Function","concat","prop","qutil","MAX_URL_LENGTH","normalizeOperations","operations","returnList","ops","_concat","arr","_normalizePlainObjects","opn","arg","_normalizeStructuredObjects","operation","name","params","_normalizeObject","_normalizeLiterals","_normalizeArrays","splitGetFactory","httpOptions","options","http","getValue","getFinalUrl","data","replace","queryParams","questionIdx","include","dtd","paramsCopy","urlNoIncludes","diff","oldSuccess","success","noop","oldError","error","currIncludes","includeOpts","currLength","variable","pop","reqs","map","reqParams","get","when","isValid","reject","firstResponse","isObject","isRunAPI","variables","aggregateRun","idx","aggregatedRuns","runs","idxRun","id","aggregatedVariables","vars","inherit","C","P","__super","constructor","dest","call","current","j","base","props","staticProps","parent","child","hasOwnProperty","qutils","config","defaults","contentType","headers","statusCode",404,"parameterParser","xhrFields","withCredentials","transportOptions","d","isFunction","connect","method","connectOptions","type","ALLOWED_TO_BE_FUNCTIONS","logLevel","console","log","oldSuccessFn","response","ajaxStatus","ajaxReq","beforeSend","xhr","settings","requestUrl","ajax","publicAPI","ajaxOptions","splitGet","post","patch","put","delete","delimiter","head","epiVersion","API_PROTOCOL","HOST_API_MAPPING","forio.com","foriodev.com","publicExports","protocol","host","window","location","appPath","path","pathname","accountPath","accnt","projectPath","prj","versionPath","isLocalhost","getAPIPath","PROJECT_APIS","apiPath","urlService","serviceOptions","server","setEnv","env","property","set","ConfigService","StorageFactory","rutil","_pick","TransportFactory","VariablesService","synchronous","token","account","project","filter","autoRestore","urlConfig","getFilterURL","addAutoRestoreHeader","isFilterRunId","autorestoreOpts","X-AutoRestore","Authorization","setFilterOrThrowError","Error","publicAsyncAPI","create","createOptions","runApiParams","model","outputModifier","load","runID","filters","save","attributes","do","opsArgs","postOptions","prms","serial","opParams","me","$d","doSingleOp","op","shift","parallel","queue","i","done","publicSyncAPI","getCurrentConfig","vs","runService","getContents","filePath","folderType","getURL","attrs","root","domain","q","saveAs","remove","keys","userName","password","login","resp","status","statusMessage","postParams","logout","apiBase","assignmentEndpoint","apiEndpoint","projectEndpoint","group","setIdFilterOrThrowError","validateModelOrThrowError","worldApiParams","update","whitelist","updateOptions","deleteOptions","updateConfig","getOptions","getWorldsForUser","userId","worldId","addUsers","users","u","updateUser","user","patchOptions","removeUser","getCurrentRunId","getCurrentWorldForUser","groupName","worlds","sort","a","b","Date","lastModified","currentWorld","deleteRun","newRunForWorld","currentRunOptions","autoAssign","opt","maxUsers","getProjectSettings","parseRunIdOrError","runId","replay","replayOptions","action","clone","toQFilter","toIdFilters","getFilters","threshold","getById","groupId","getFinalParams","patchUserActiveField","active","getGroupsForUser","isString","objParams","getParms","getGroupDetails","makeUserActive","makeUserInactive","keyNames","session","parse","EPI_SESSION_KEY","EPI_COOKIE_KEY","scope","fullUrl","processData","assetApiParams","scopeConfig","validateFilename","filename","validateUrlParams","partKeys","buildUrl","parts","upload","toLowerCase","FormData","urlOptions","getServiceOptions","files","fullPathFiles","file","assetUrl","setOptions","document","cookie","encodeURIComponent","cookieReg","RegExp","decodeURIComponent","remOptions","destroy","aKeys","nIdx","cookieKey","RunService","validFilter","saved","getRuns","loadVariables","meta","_getService","archive","getRun","patchRunService","patched","orig","reservedOps","Object","specialOperations","StrategyCtor","strategiesMap","reset","runServiceOptions","saveSession","userInfo","serialized","auth_token","getSession","isLocal","authAdapter","AuthAdapter","MemberAdapter","Buffer","_findUserInGroup","members","adapterOptions","outSuccess","outError","accountName","projectName","decodeToken","encoded","decode","atob","toString","handleGroupError","message","statusText","handleSuccess","access_token","userGroupOpts","getUserGroups","user_id","memberInfo","auth","userGroups","groupSelection","sessionInfo","filteredGroups","grep","resGroup","sessionInfoWithGroup","isFac","role","removeCookieFn","getToken","memberAdapter","getCurrentUserSessionInfo","buildStrategy","worldApi","WorldApi","world","_auth","getCurrentWorld","getCurrentRun","getAndRestoreLatestRun","currentWorldId","runOpts","rm","curUserId","curGroupName","getFromSettingsOrSessionOrError","sessionKeyName","EpicenterChannelManager","defaultCometOptions","urlOpts","getGroupChannel","baseTopic","getChannel","getWorldChannel","worldid","getUserChannel","userid","getPresenceChannel","channel","lastPingTime","PING_INTERVAL","subscribe","notification","incomingUserId","trigger","online","valueOf","setInterval","publish","now","getDataChannel","collection","oldsubs","topic","callback","context","callbackWithCleanData","payload","subType","date","actualData","topicResolver","channelOptions","makeName","channelName","newName","topics","subscriptionIds","opts","batch","returnObjs","warn","unsubscribe","on","event","off","ConditionalStrategy","Strategy","createIf","setRunInSession","sessionKey","sessionStore","makeSeq","Base","SessionStore","UrlService","STRATEGY_SESSION_KEY","condition","runOptions","runOptionsWithScope","userSession","freshlyCreated","runSession","_loadAndCheck","shouldCreate","msg","getResponseHeader","initialized","cometd","websocketEnabled","shareConnection","currentSubscriptions","_cometd","Cometd","isConnected","connectionBroken","connectionSucceeded","configure","addListener","wasConnected","successful","subs","resubscribe","handshake","subid","unsubs","removed","new-if-initialized","new-if-persisted","new-if-missing","always-new","multiplayer","persistent-single-player","none","typedArraySupport","Bar","Uint8Array","foo","subarray","byteLength","e","kMaxLength","TYPED_ARRAY_SUPPORT","fromNumber","fromString","fromObject","that","allocate","checked","string","encoding","write","object","isBuffer","fromBuffer","fromArray","TypeError","ArrayBuffer","buffer","fromTypedArray","fromArrayBuffer","fromArrayLike","fromJsonObject","copy","array","_augment","__proto__","_isBuffer","fromPool","poolSize","rootParent","RangeError","SlowBuffer","subject","buf","len","loweredCase","utf8ToBytes","base64ToBytes","slowToString","end","Infinity","hexSlice","utf8Slice","asciiSlice","binarySlice","base64Slice","utf16leSlice","hexWrite","offset","Number","remaining","strLen","parsed","parseInt","substr","isNaN","utf8Write","blitBuffer","asciiWrite","asciiToBytes","binaryWrite","base64Write","ucs2Write","utf16leToBytes","base64","fromByteArray","Math","min","firstByte","codePoint","bytesPerSequence","secondByte","thirdByte","fourthByte","tempCodePoint","decodeCodePointsArray","codePoints","MAX_ARGUMENTS_LENGTH","fromCharCode","ret","out","toHex","bytes","checkOffset","ext","checkInt","max","objectWriteUInt16","littleEndian","objectWriteUInt32","checkIEEE754","writeFloat","noAssert","ieee754","writeDouble","base64clean","str","stringtrim","INVALID_BASE64_RE","n","units","leadSurrogate","charCodeAt","byteArray","c","hi","lo","toByteArray","src","dst","INSPECT_MAX_BYTES","compare","x","y","isEncoding","pos","item","equals","inspect","match","byteOffset","arrayIndexOf","foundIndex","readUInt8","v","writeUInt8","isFinite","swap","toJSON","_arr","newBuf","sliceLen","readUIntLE","mul","readUIntBE","readUInt16LE","readUInt16BE","readUInt32LE","readUInt32BE","readIntLE","pow","readIntBE","readInt8","readInt16LE","readInt16BE","readInt32LE","readInt32BE","readFloatLE","read","readFloatBE","readDoubleLE","readDoubleBE","writeUIntLE","writeUIntBE","floor","writeUInt16LE","writeUInt16BE","writeUInt32LE","writeUInt32BE","writeIntLE","limit","sub","writeIntBE","writeInt8","writeInt16LE","writeInt16BE","writeInt32LE","writeInt32BE","writeFloatLE","writeFloatBE","writeDoubleLE","writeDoubleBE","target","targetStart","_set","fill","toArrayBuffer","BP","toLocaleString","IdentityStrategy","WorldApiAdapter","_loadRun","loadRunFromWorld","serverError","StateApi","_store","stateApi","_restoreRun","_getAllRuns","user.id","scope.group","dateComp","latestRun","shouldReplay","isLE","mLen","nBytes","m","eLen","eMax","eBias","nBits","s","NaN","rt","abs","LN2","lookup","elt","code","PLUS","PLUS_URL_SAFE","SLASH","SLASH_URL_SAFE","NUMBER","UPPER","LOWER","b64ToByteArray","b64","L","l","tmp","placeHolders","Arr","uint8ToBase64","uint8","encode","num","tripletToBase64","temp","extraBytes","output","base64js"],"mappings":"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","file":"bundle.js","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && url.length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = '?include='.length;\n var variable = include.pop();\n while (variable) {\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + variable.length + 1 < diff) {\n currIncludes.push(variable);\n currLength += variable.length + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + variable.length;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ##File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n // config || (config = configService.get());\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || store.get('epicenter.token') || '',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: '',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {String} `folderType` One of Model|Static|Node\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, folderType, options) {\n var path = folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ##Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * ##Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: '',\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n domain: 'forio.com',\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ##Authentication API Service\n *\n * The Authentication API Service provides methods for logging in and logging out. On login, this service creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n * auth.logout();\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n /**\n * Logs user out from specified accounts.\n * Epicenter logout is not implemented yet, added a dummy promise that gets automatically resolved.\n *\n * **Example**\n *\n * auth.logout();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ##World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n $.extend(params, _pick(serviceOptions, ['account', 'project', 'group']));\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ##State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ##User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ##Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: '',\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar keyNames = require('../managers/key-names');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n var session = JSON.parse(store.get(keyNames.EPI_SESSION_KEY) || '{}');\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get(keyNames.EPI_COOKIE_KEY) || '',\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: session.userId,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n var serviceOptions = $.extend(true, {}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.forio.com'\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n\n document.cookie = encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookieReg = new RegExp('(?:(?:^|.*;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$');\n var val = document.cookie.replace(cookieReg, '$1');\n val = decodeURIComponent(val) || null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n\n document.cookie = encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var aKeys = document.cookie.replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* ####Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar ConfigService = require('../service/configuration-service');\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar StorageFactory = require('../store/store-factory');\nvar Buffer = require('buffer').Buffer;\nvar keyNames = require('./key-names');\n\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY;\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar store;\nvar token;\nvar session;\n\nfunction saveSession(userInfo, store) {\n var serialized = JSON.stringify(userInfo);\n store.set(EPI_SESSION_KEY, serialized);\n\n //jshint camelcase: false\n //jscs:disable\n store.set(EPI_COOKIE_KEY, userInfo.auth_token);\n}\n\nfunction getSession(store) {\n var session = store.get(EPI_SESSION_KEY) || '{}';\n return JSON.parse(session);\n}\n\nfunction AuthManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n var urlConfig = new ConfigService(this.options).get('server');\n this.isLocal = urlConfig.isLocalhost();\n\n if (!this.options.account) {\n this.options.account = urlConfig.accountPath;\n }\n\n // null might specified to disable project filtering\n if (this.options.project === undefined) {\n this.options.project = urlConfig.projectPath;\n }\n\n this.store = new StorageFactory(this.options.store);\n session = getSession(this.store);\n token = this.store.get(EPI_COOKIE_KEY) || '';\n //jshint camelcase: false\n //jscs:disable\n this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token });\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(memberInfo, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n var groupSelection = group.groupId;\n data.groupSelection[adapterOptions.project] = groupSelection;\n var sessionInfoWithGroup = $.extend({}, sessionInfo, {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n });\n saveSession(sessionInfoWithGroup, _this.store);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n }).fail($d.reject);\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var adapterOptions = $.extend(true, { token: token }, this.options, options);\n\n var removeCookieFn = function (response) {\n store.remove(EPI_COOKIE_KEY, adapterOptions);\n store.remove(EPI_SESSION_KEY, adapterOptions);\n token = '';\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = $.extend(true, this.options, options);\n\n var $d = $.Deferred();\n if (token) {\n $d.resolve(token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = $.extend(true, { success: $.noop }, this.options, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return getSession(this.store, options);\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `server` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `server.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `server.project` Epicenter project id.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\n\nvar AuthManager = require('./auth-manager');\n\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n var userInfo = session.getCurrentUserSessionInfo();\n\n var defaults = {\n account: userInfo.account,\n project: userInfo.project,\n };\n var defaultCometOptions = $.extend(true, {}, defaults, userInfo, options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getDataChannel('survey-responses');\n * gc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionStore = require('../../store/store-factory');\nvar classFrom = require('../../util/inherit');\nvar UrlService = require('../../service/url-config-service');\nvar AuthManager = require('../auth-manager');\n\nvar sessionStore = new SessionStore({});\nvar urlService = new UrlService();\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, path) {\n if (!path) {\n if (!urlService.isLocalhost()) {\n path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/');\n // make sure we don't get consecuteive '/' so we have a valid path for the session\n path = path.replace(/\\/{2,}/g,'/');\n } else {\n path = '';\n }\n }\n // set the seesionKey for the run\n sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path });\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.options.path);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession);\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","'use strict';\n\nmodule.exports = {\n EPI_COOKIE_KEY: 'epicenter.project.token',\n EPI_SESSION_KEY: 'epicenter.user.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","'use strict';\n\nvar Channel = require('../service/channel-service');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n }\n };\n var defaultCometOptions = $.extend(true, {}, defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake();\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('is-array')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\nBuffer.poolSize = 8192 // not used by this implementation\n\nvar rootParent = {}\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property\n * on objects.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\nfunction typedArraySupport () {\n function Bar () {}\n try {\n var arr = new Uint8Array(1)\n arr.foo = function () { return 42 }\n arr.constructor = Bar\n return arr.foo() === 42 && // typed array instances can be augmented\n arr.constructor === Bar && // constructor can be set\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\n/**\n * Class: Buffer\n * =============\n *\n * The Buffer constructor returns instances of `Uint8Array` that are augmented\n * with function properties for all the node `Buffer` API functions. We use\n * `Uint8Array` so that square bracket notation works as expected -- it returns\n * a single octet.\n *\n * By augmenting the instances, we can avoid modifying the `Uint8Array`\n * prototype.\n */\nfunction Buffer (arg) {\n if (!(this instanceof Buffer)) {\n // Avoid going through an ArgumentsAdaptorTrampoline in the common case.\n if (arguments.length > 1) return new Buffer(arg, arguments[1])\n return new Buffer(arg)\n }\n\n this.length = 0\n this.parent = undefined\n\n // Common case.\n if (typeof arg === 'number') {\n return fromNumber(this, arg)\n }\n\n // Slightly less common case.\n if (typeof arg === 'string') {\n return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')\n }\n\n // Unusual.\n return fromObject(this, arg)\n}\n\nfunction fromNumber (that, length) {\n that = allocate(that, length < 0 ? 0 : checked(length) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < length; i++) {\n that[i] = 0\n }\n }\n return that\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'\n\n // Assumption: byteLength() return value is always < kMaxLength.\n var length = byteLength(string, encoding) | 0\n that = allocate(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromObject (that, object) {\n if (Buffer.isBuffer(object)) return fromBuffer(that, object)\n\n if (isArray(object)) return fromArray(that, object)\n\n if (object == null) {\n throw new TypeError('must start with number, buffer, array or string')\n }\n\n if (typeof ArrayBuffer !== 'undefined') {\n if (object.buffer instanceof ArrayBuffer) {\n return fromTypedArray(that, object)\n }\n if (object instanceof ArrayBuffer) {\n return fromArrayBuffer(that, object)\n }\n }\n\n if (object.length) return fromArrayLike(that, object)\n\n return fromJsonObject(that, object)\n}\n\nfunction fromBuffer (that, buffer) {\n var length = checked(buffer.length) | 0\n that = allocate(that, length)\n buffer.copy(that, 0, 0, length)\n return that\n}\n\nfunction fromArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Duplicate of fromArray() to keep fromArray() monomorphic.\nfunction fromTypedArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n // Truncating the elements is probably not what people expect from typed\n // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior\n // of the old Buffer constructor.\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n array.byteLength\n that = Buffer._augment(new Uint8Array(array))\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromTypedArray(that, new Uint8Array(array))\n }\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.\n// Returns a zero-length buffer for inputs that don't conform to the spec.\nfunction fromJsonObject (that, object) {\n var array\n var length = 0\n\n if (object.type === 'Buffer' && isArray(object.data)) {\n array = object.data\n length = checked(array.length) | 0\n }\n that = allocate(that, length)\n\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n}\n\nfunction allocate (that, length) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = Buffer._augment(new Uint8Array(length))\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that.length = length\n that._isBuffer = true\n }\n\n var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1\n if (fromPool) that.parent = rootParent\n\n return that\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (subject, encoding) {\n if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)\n\n var buf = new Buffer(subject, encoding)\n delete buf.parent\n return buf\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n var i = 0\n var len = Math.min(x, y)\n while (i < len) {\n if (a[i] !== b[i]) break\n\n ++i\n }\n\n if (i !== len) {\n x = a[i]\n y = b[i]\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')\n\n if (list.length === 0) {\n return new Buffer(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; i++) {\n length += list[i].length\n }\n }\n\n var buf = new Buffer(length)\n var pos = 0\n for (i = 0; i < list.length; i++) {\n var item = list[i]\n item.copy(buf, pos)\n pos += item.length\n }\n return buf\n}\n\nfunction byteLength (string, encoding) {\n if (typeof string !== 'string') string = '' + string\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n // Deprecated\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\n// pre-set for values that may exist in the future\nBuffer.prototype.length = undefined\nBuffer.prototype.parent = undefined\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n start = start | 0\n end = end === undefined || end === Infinity ? this.length : end | 0\n\n if (!encoding) encoding = 'utf8'\n if (start < 0) start = 0\n if (end > this.length) end = this.length\n if (end <= start) return ''\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return 0\n return Buffer.compare(this, b)\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset) {\n if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff\n else if (byteOffset < -0x80000000) byteOffset = -0x80000000\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n if (val.length === 0) return -1 // special case: looking for empty string always fails\n return String.prototype.indexOf.call(this, val, byteOffset)\n }\n if (Buffer.isBuffer(val)) {\n return arrayIndexOf(this, val, byteOffset)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset)\n }\n\n function arrayIndexOf (arr, val, byteOffset) {\n var foundIndex = -1\n for (var i = 0; byteOffset + i < arr.length; i++) {\n if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex\n } else {\n foundIndex = -1\n }\n }\n return -1\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\n// `get` is deprecated\nBuffer.prototype.get = function get (offset) {\n console.log('.get() is deprecated. Access using array indexes instead.')\n return this.readUInt8(offset)\n}\n\n// `set` is deprecated\nBuffer.prototype.set = function set (v, offset) {\n console.log('.set() is deprecated. Access using array indexes instead.')\n return this.writeUInt8(v, offset)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; i++) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) throw new Error('Invalid hex string')\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n var swap = encoding\n encoding = offset\n offset = length | 0\n length = swap\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; i++) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = Buffer._augment(this.subarray(start, end))\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; i++) {\n newBuf[i] = this[i + start]\n }\n }\n\n if (newBuf.length) newBuf.parent = this.parent || this\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n if (offset < 0) throw new RangeError('index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; i--) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; i++) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n target._set(this.subarray(start, start + len), targetStart)\n }\n\n return len\n}\n\n// fill(value, start=0, end=buffer.length)\nBuffer.prototype.fill = function fill (value, start, end) {\n if (!value) value = 0\n if (!start) start = 0\n if (!end) end = this.length\n\n if (end < start) throw new RangeError('end < start')\n\n // Fill 0 bytes; we're done\n if (end === start) return\n if (this.length === 0) return\n\n if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')\n if (end < 0 || end > this.length) throw new RangeError('end out of bounds')\n\n var i\n if (typeof value === 'number') {\n for (i = start; i < end; i++) {\n this[i] = value\n }\n } else {\n var bytes = utf8ToBytes(value.toString())\n var len = bytes.length\n for (i = start; i < end; i++) {\n this[i] = bytes[i % len]\n }\n }\n\n return this\n}\n\n/**\n * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.\n * Added in Node 0.12. Only available in browsers that support ArrayBuffer.\n */\nBuffer.prototype.toArrayBuffer = function toArrayBuffer () {\n if (typeof Uint8Array !== 'undefined') {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n return (new Buffer(this)).buffer\n } else {\n var buf = new Uint8Array(this.length)\n for (var i = 0, len = buf.length; i < len; i += 1) {\n buf[i] = this[i]\n }\n return buf.buffer\n }\n } else {\n throw new TypeError('Buffer.toArrayBuffer not supported in this browser')\n }\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar BP = Buffer.prototype\n\n/**\n * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods\n */\nBuffer._augment = function _augment (arr) {\n arr.constructor = Buffer\n arr._isBuffer = true\n\n // save reference to original Uint8Array set method before overwriting\n arr._set = arr.set\n\n // deprecated\n arr.get = BP.get\n arr.set = BP.set\n\n arr.write = BP.write\n arr.toString = BP.toString\n arr.toLocaleString = BP.toString\n arr.toJSON = BP.toJSON\n arr.equals = BP.equals\n arr.compare = BP.compare\n arr.indexOf = BP.indexOf\n arr.copy = BP.copy\n arr.slice = BP.slice\n arr.readUIntLE = BP.readUIntLE\n arr.readUIntBE = BP.readUIntBE\n arr.readUInt8 = BP.readUInt8\n arr.readUInt16LE = BP.readUInt16LE\n arr.readUInt16BE = BP.readUInt16BE\n arr.readUInt32LE = BP.readUInt32LE\n arr.readUInt32BE = BP.readUInt32BE\n arr.readIntLE = BP.readIntLE\n arr.readIntBE = BP.readIntBE\n arr.readInt8 = BP.readInt8\n arr.readInt16LE = BP.readInt16LE\n arr.readInt16BE = BP.readInt16BE\n arr.readInt32LE = BP.readInt32LE\n arr.readInt32BE = BP.readInt32BE\n arr.readFloatLE = BP.readFloatLE\n arr.readFloatBE = BP.readFloatBE\n arr.readDoubleLE = BP.readDoubleLE\n arr.readDoubleBE = BP.readDoubleBE\n arr.writeUInt8 = BP.writeUInt8\n arr.writeUIntLE = BP.writeUIntLE\n arr.writeUIntBE = BP.writeUIntBE\n arr.writeUInt16LE = BP.writeUInt16LE\n arr.writeUInt16BE = BP.writeUInt16BE\n arr.writeUInt32LE = BP.writeUInt32LE\n arr.writeUInt32BE = BP.writeUInt32BE\n arr.writeIntLE = BP.writeIntLE\n arr.writeIntBE = BP.writeIntBE\n arr.writeInt8 = BP.writeInt8\n arr.writeInt16LE = BP.writeInt16LE\n arr.writeInt16BE = BP.writeInt16BE\n arr.writeInt32LE = BP.writeInt32LE\n arr.writeInt32BE = BP.writeInt32BE\n arr.writeFloatLE = BP.writeFloatLE\n arr.writeFloatBE = BP.writeFloatBE\n arr.writeDoubleLE = BP.writeDoubleLE\n arr.writeDoubleBE = BP.writeDoubleBE\n arr.fill = BP.fill\n arr.inspect = BP.inspect\n arr.toArrayBuffer = BP.toArrayBuffer\n\n return arr\n}\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; i++) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; i++) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n;(function (exports) {\n\t'use strict';\n\n var Arr = (typeof Uint8Array !== 'undefined')\n ? Uint8Array\n : Array\n\n\tvar PLUS = '+'.charCodeAt(0)\n\tvar SLASH = '/'.charCodeAt(0)\n\tvar NUMBER = '0'.charCodeAt(0)\n\tvar LOWER = 'a'.charCodeAt(0)\n\tvar UPPER = 'A'.charCodeAt(0)\n\tvar PLUS_URL_SAFE = '-'.charCodeAt(0)\n\tvar SLASH_URL_SAFE = '_'.charCodeAt(0)\n\n\tfunction decode (elt) {\n\t\tvar code = elt.charCodeAt(0)\n\t\tif (code === PLUS ||\n\t\t code === PLUS_URL_SAFE)\n\t\t\treturn 62 // '+'\n\t\tif (code === SLASH ||\n\t\t code === SLASH_URL_SAFE)\n\t\t\treturn 63 // '/'\n\t\tif (code < NUMBER)\n\t\t\treturn -1 //no match\n\t\tif (code < NUMBER + 10)\n\t\t\treturn code - NUMBER + 26 + 26\n\t\tif (code < UPPER + 26)\n\t\t\treturn code - UPPER\n\t\tif (code < LOWER + 26)\n\t\t\treturn code - LOWER + 26\n\t}\n\n\tfunction b64ToByteArray (b64) {\n\t\tvar i, j, l, tmp, placeHolders, arr\n\n\t\tif (b64.length % 4 > 0) {\n\t\t\tthrow new Error('Invalid string. Length must be a multiple of 4')\n\t\t}\n\n\t\t// the number of equal signs (place holders)\n\t\t// if there are two placeholders, than the two characters before it\n\t\t// represent one byte\n\t\t// if there is only one, then the three characters before it represent 2 bytes\n\t\t// this is just a cheap hack to not do indexOf twice\n\t\tvar len = b64.length\n\t\tplaceHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0\n\n\t\t// base64 is 4/3 + up to two characters of the original data\n\t\tarr = new Arr(b64.length * 3 / 4 - placeHolders)\n\n\t\t// if there are placeholders, only get up to the last complete 4 chars\n\t\tl = placeHolders > 0 ? b64.length - 4 : b64.length\n\n\t\tvar L = 0\n\n\t\tfunction push (v) {\n\t\t\tarr[L++] = v\n\t\t}\n\n\t\tfor (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))\n\t\t\tpush((tmp & 0xFF0000) >> 16)\n\t\t\tpush((tmp & 0xFF00) >> 8)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\tif (placeHolders === 2) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)\n\t\t\tpush(tmp & 0xFF)\n\t\t} else if (placeHolders === 1) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)\n\t\t\tpush((tmp >> 8) & 0xFF)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\treturn arr\n\t}\n\n\tfunction uint8ToBase64 (uint8) {\n\t\tvar i,\n\t\t\textraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes\n\t\t\toutput = \"\",\n\t\t\ttemp, length\n\n\t\tfunction encode (num) {\n\t\t\treturn lookup.charAt(num)\n\t\t}\n\n\t\tfunction tripletToBase64 (num) {\n\t\t\treturn encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)\n\t\t}\n\n\t\t// go through the array every three bytes, we'll deal with trailing stuff later\n\t\tfor (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n\t\t\ttemp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n\t\t\toutput += tripletToBase64(temp)\n\t\t}\n\n\t\t// pad the end with zeros, but make sure to not forget the extra bytes\n\t\tswitch (extraBytes) {\n\t\t\tcase 1:\n\t\t\t\ttemp = uint8[uint8.length - 1]\n\t\t\t\toutput += encode(temp >> 2)\n\t\t\t\toutput += encode((temp << 4) & 0x3F)\n\t\t\t\toutput += '=='\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\ttemp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])\n\t\t\t\toutput += encode(temp >> 10)\n\t\t\t\toutput += encode((temp >> 4) & 0x3F)\n\t\t\t\toutput += encode((temp << 2) & 0x3F)\n\t\t\t\toutput += '='\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn output\n\t}\n\n\texports.toByteArray = b64ToByteArray\n\texports.fromByteArray = uint8ToBase64\n}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))\n","\n/**\n * isArray\n */\n\nvar isArray = Array.isArray;\n\n/**\n * toString\n */\n\nvar str = Object.prototype.toString;\n\n/**\n * Whether or not the given `val`\n * is an array.\n *\n * example:\n *\n * isArray([]);\n * // > true\n * isArray(arguments);\n * // > false\n * isArray('');\n * // > false\n *\n * @param {mixed} val\n * @return {bool}\n */\n\nmodule.exports = isArray || function (val) {\n return !! val && '[object Array]' == str.call(val);\n};\n"]} \ No newline at end of file From c37658a5c5330c728503a413efa7f2eb7ab633f9 Mon Sep 17 00:00:00 2001 From: john zhang Date: Fri, 26 Feb 2016 16:55:46 -0800 Subject: [PATCH 12/14] fix reference for store on aut manager store --- src/managers/auth-manager.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/managers/auth-manager.js b/src/managers/auth-manager.js index 80a08124..26ca6346 100644 --- a/src/managers/auth-manager.js +++ b/src/managers/auth-manager.js @@ -260,11 +260,12 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * @param {Object} `options` (Optional) Overrides for configuration options. */ logout: function (options) { + var _this = this; var adapterOptions = $.extend(true, { token: token }, this.options, options); var removeCookieFn = function (response) { - store.remove(EPI_COOKIE_KEY, adapterOptions); - store.remove(EPI_SESSION_KEY, adapterOptions); + _this.store.remove(EPI_COOKIE_KEY, adapterOptions); + _this.store.remove(EPI_SESSION_KEY, adapterOptions); token = ''; }; From 465e5e5043767881ca4373709071791f70593141 Mon Sep 17 00:00:00 2001 From: john zhang Date: Fri, 26 Feb 2016 16:56:14 -0800 Subject: [PATCH 13/14] fix linter --- src/managers/auth-manager.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/managers/auth-manager.js b/src/managers/auth-manager.js index 26ca6346..e20ba047 100644 --- a/src/managers/auth-manager.js +++ b/src/managers/auth-manager.js @@ -48,7 +48,6 @@ var defaults = { var EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY; var EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY; -var store; var token; var session; From 921c0bfde87aa1153fd0ed3bd7b390930f821d21 Mon Sep 17 00:00:00 2001 From: Molly Jones Date: Fri, 26 Feb 2016 16:58:33 -0800 Subject: [PATCH 14/14] more building & testing --- dist/epicenter.js | 8 ++++---- dist/epicenter.min.js | 2 +- dist/epicenter.min.js.map | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dist/epicenter.js b/dist/epicenter.js index dc1ae32f..9ea89f31 100644 --- a/dist/epicenter.js +++ b/dist/epicenter.js @@ -1918,7 +1918,6 @@ var defaults = { var EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY; var EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY; -var store; var token; var session; @@ -2130,11 +2129,12 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * @param {Object} `options` (Optional) Overrides for configuration options. */ logout: function (options) { + var _this = this; var adapterOptions = $.extend(true, { token: token }, this.options, options); var removeCookieFn = function (response) { - store.remove(EPI_COOKIE_KEY, adapterOptions); - store.remove(EPI_SESSION_KEY, adapterOptions); + _this.store.remove(EPI_COOKIE_KEY, adapterOptions); + _this.store.remove(EPI_SESSION_KEY, adapterOptions); token = ''; }; @@ -7451,4 +7451,4 @@ module.exports = (function () { }()); },{"./query-util":44}]},{},[6]) -//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL25vZGVfbW9kdWxlcy9pZWVlNzU0L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvaXMtYXJyYXkvaW5kZXguanMiLCJzcmMvYXBpLXZlcnNpb24uanNvbiIsInNyYy9hcHAuanMiLCJzcmMvbWFuYWdlcnMvYXV0aC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2NoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2tleS1uYW1lcy5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9hbHdheXMtbmV3LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2lkZW50aXR5LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL211bHRpcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcC5qcyIsInNyYy9tYW5hZ2Vycy9zY2VuYXJpby1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3NwZWNpYWwtb3BlcmF0aW9ucy5qcyIsInNyYy9tYW5hZ2Vycy93b3JsZC1tYW5hZ2VyLmpzIiwic3JjL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyLmpzIiwic3JjL3N0b3JlL2Nvb2tpZS1zdG9yZS5qcyIsInNyYy9zdG9yZS9zdG9yZS1mYWN0b3J5LmpzIiwic3JjL3RyYW5zcG9ydC9hamF4LWh0dHAtdHJhbnNwb3J0LmpzIiwic3JjL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5LmpzIiwic3JjL3V0aWwvaW5oZXJpdC5qcyIsInNyYy91dGlsL21ha2Utc2VxdWVuY2UuanMiLCJzcmMvdXRpbC9vYmplY3QtdXRpbC5qcyIsInNyYy91dGlsL3F1ZXJ5LXV0aWwuanMiLCJzcmMvdXRpbC9ydW4tdXRpbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN4Z0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNVdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6T0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdFFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4ZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6SkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM3VCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8qIVxuICogVGhlIGJ1ZmZlciBtb2R1bGUgZnJvbSBub2RlLmpzLCBmb3IgdGhlIGJyb3dzZXIuXG4gKlxuICogQGF1dGhvciAgIEZlcm9zcyBBYm91a2hhZGlqZWggPGZlcm9zc0BmZXJvc3Mub3JnPiA8aHR0cDovL2Zlcm9zcy5vcmc+XG4gKiBAbGljZW5zZSAgTUlUXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIG5vLXByb3RvICovXG5cbnZhciBiYXNlNjQgPSByZXF1aXJlKCdiYXNlNjQtanMnKVxudmFyIGllZWU3NTQgPSByZXF1aXJlKCdpZWVlNzU0JylcbnZhciBpc0FycmF5ID0gcmVxdWlyZSgnaXMtYXJyYXknKVxuXG5leHBvcnRzLkJ1ZmZlciA9IEJ1ZmZlclxuZXhwb3J0cy5TbG93QnVmZmVyID0gU2xvd0J1ZmZlclxuZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFUyA9IDUwXG5CdWZmZXIucG9vbFNpemUgPSA4MTkyIC8vIG5vdCB1c2VkIGJ5IHRoaXMgaW1wbGVtZW50YXRpb25cblxudmFyIHJvb3RQYXJlbnQgPSB7fVxuXG4vKipcbiAqIElmIGBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVGA6XG4gKiAgID09PSB0cnVlICAgIFVzZSBVaW50OEFycmF5IGltcGxlbWVudGF0aW9uIChmYXN0ZXN0KVxuICogICA9PT0gZmFsc2UgICBVc2UgT2JqZWN0IGltcGxlbWVudGF0aW9uIChtb3N0IGNvbXBhdGlibGUsIGV2ZW4gSUU2KVxuICpcbiAqIEJyb3dzZXJzIHRoYXQgc3VwcG9ydCB0eXBlZCBhcnJheXMgYXJlIElFIDEwKywgRmlyZWZveCA0KywgQ2hyb21lIDcrLCBTYWZhcmkgNS4xKyxcbiAqIE9wZXJhIDExLjYrLCBpT1MgNC4yKy5cbiAqXG4gKiBEdWUgdG8gdmFyaW91cyBicm93c2VyIGJ1Z3MsIHNvbWV0aW1lcyB0aGUgT2JqZWN0IGltcGxlbWVudGF0aW9uIHdpbGwgYmUgdXNlZCBldmVuXG4gKiB3aGVuIHRoZSBicm93c2VyIHN1cHBvcnRzIHR5cGVkIGFycmF5cy5cbiAqXG4gKiBOb3RlOlxuICpcbiAqICAgLSBGaXJlZm94IDQtMjkgbGFja3Mgc3VwcG9ydCBmb3IgYWRkaW5nIG5ldyBwcm9wZXJ0aWVzIHRvIGBVaW50OEFycmF5YCBpbnN0YW5jZXMsXG4gKiAgICAgU2VlOiBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD02OTU0MzguXG4gKlxuICogICAtIFNhZmFyaSA1LTcgbGFja3Mgc3VwcG9ydCBmb3IgY2hhbmdpbmcgdGhlIGBPYmplY3QucHJvdG90eXBlLmNvbnN0cnVjdG9yYCBwcm9wZXJ0eVxuICogICAgIG9uIG9iamVjdHMuXG4gKlxuICogICAtIENocm9tZSA5LTEwIGlzIG1pc3NpbmcgdGhlIGBUeXBlZEFycmF5LnByb3RvdHlwZS5zdWJhcnJheWAgZnVuY3Rpb24uXG4gKlxuICogICAtIElFMTAgaGFzIGEgYnJva2VuIGBUeXBlZEFycmF5LnByb3RvdHlwZS5zdWJhcnJheWAgZnVuY3Rpb24gd2hpY2ggcmV0dXJucyBhcnJheXMgb2ZcbiAqICAgICBpbmNvcnJlY3QgbGVuZ3RoIGluIHNvbWUgc2l0dWF0aW9ucy5cblxuICogV2UgZGV0ZWN0IHRoZXNlIGJ1Z2d5IGJyb3dzZXJzIGFuZCBzZXQgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYCB0byBgZmFsc2VgIHNvIHRoZXlcbiAqIGdldCB0aGUgT2JqZWN0IGltcGxlbWVudGF0aW9uLCB3aGljaCBpcyBzbG93ZXIgYnV0IGJlaGF2ZXMgY29ycmVjdGx5LlxuICovXG5CdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCA9IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUICE9PSB1bmRlZmluZWRcbiAgPyBnbG9iYWwuVFlQRURfQVJSQVlfU1VQUE9SVFxuICA6IHR5cGVkQXJyYXlTdXBwb3J0KClcblxuZnVuY3Rpb24gdHlwZWRBcnJheVN1cHBvcnQgKCkge1xuICBmdW5jdGlvbiBCYXIgKCkge31cbiAgdHJ5IHtcbiAgICB2YXIgYXJyID0gbmV3IFVpbnQ4QXJyYXkoMSlcbiAgICBhcnIuZm9vID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gNDIgfVxuICAgIGFyci5jb25zdHJ1Y3RvciA9IEJhclxuICAgIHJldHVybiBhcnIuZm9vKCkgPT09IDQyICYmIC8vIHR5cGVkIGFycmF5IGluc3RhbmNlcyBjYW4gYmUgYXVnbWVudGVkXG4gICAgICAgIGFyci5jb25zdHJ1Y3RvciA9PT0gQmFyICYmIC8vIGNvbnN0cnVjdG9yIGNhbiBiZSBzZXRcbiAgICAgICAgdHlwZW9mIGFyci5zdWJhcnJheSA9PT0gJ2Z1bmN0aW9uJyAmJiAvLyBjaHJvbWUgOS0xMCBsYWNrIGBzdWJhcnJheWBcbiAgICAgICAgYXJyLnN1YmFycmF5KDEsIDEpLmJ5dGVMZW5ndGggPT09IDAgLy8gaWUxMCBoYXMgYnJva2VuIGBzdWJhcnJheWBcbiAgfSBjYXRjaCAoZSkge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbmZ1bmN0aW9uIGtNYXhMZW5ndGggKCkge1xuICByZXR1cm4gQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRcbiAgICA/IDB4N2ZmZmZmZmZcbiAgICA6IDB4M2ZmZmZmZmZcbn1cblxuLyoqXG4gKiBDbGFzczogQnVmZmVyXG4gKiA9PT09PT09PT09PT09XG4gKlxuICogVGhlIEJ1ZmZlciBjb25zdHJ1Y3RvciByZXR1cm5zIGluc3RhbmNlcyBvZiBgVWludDhBcnJheWAgdGhhdCBhcmUgYXVnbWVudGVkXG4gKiB3aXRoIGZ1bmN0aW9uIHByb3BlcnRpZXMgZm9yIGFsbCB0aGUgbm9kZSBgQnVmZmVyYCBBUEkgZnVuY3Rpb25zLiBXZSB1c2VcbiAqIGBVaW50OEFycmF5YCBzbyB0aGF0IHNxdWFyZSBicmFja2V0IG5vdGF0aW9uIHdvcmtzIGFzIGV4cGVjdGVkIC0tIGl0IHJldHVybnNcbiAqIGEgc2luZ2xlIG9jdGV0LlxuICpcbiAqIEJ5IGF1Z21lbnRpbmcgdGhlIGluc3RhbmNlcywgd2UgY2FuIGF2b2lkIG1vZGlmeWluZyB0aGUgYFVpbnQ4QXJyYXlgXG4gKiBwcm90b3R5cGUuXG4gKi9cbmZ1bmN0aW9uIEJ1ZmZlciAoYXJnKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBCdWZmZXIpKSB7XG4gICAgLy8gQXZvaWQgZ29pbmcgdGhyb3VnaCBhbiBBcmd1bWVudHNBZGFwdG9yVHJhbXBvbGluZSBpbiB0aGUgY29tbW9uIGNhc2UuXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSByZXR1cm4gbmV3IEJ1ZmZlcihhcmcsIGFyZ3VtZW50c1sxXSlcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcihhcmcpXG4gIH1cblxuICB0aGlzLmxlbmd0aCA9IDBcbiAgdGhpcy5wYXJlbnQgPSB1bmRlZmluZWRcblxuICAvLyBDb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdudW1iZXInKSB7XG4gICAgcmV0dXJuIGZyb21OdW1iZXIodGhpcywgYXJnKVxuICB9XG5cbiAgLy8gU2xpZ2h0bHkgbGVzcyBjb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIGZyb21TdHJpbmcodGhpcywgYXJnLCBhcmd1bWVudHMubGVuZ3RoID4gMSA/IGFyZ3VtZW50c1sxXSA6ICd1dGY4JylcbiAgfVxuXG4gIC8vIFVudXN1YWwuXG4gIHJldHVybiBmcm9tT2JqZWN0KHRoaXMsIGFyZylcbn1cblxuZnVuY3Rpb24gZnJvbU51bWJlciAodGhhdCwgbGVuZ3RoKSB7XG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGggPCAwID8gMCA6IGNoZWNrZWQobGVuZ3RoKSB8IDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICB0aGF0W2ldID0gMFxuICAgIH1cbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tU3RyaW5nICh0aGF0LCBzdHJpbmcsIGVuY29kaW5nKSB7XG4gIGlmICh0eXBlb2YgZW5jb2RpbmcgIT09ICdzdHJpbmcnIHx8IGVuY29kaW5nID09PSAnJykgZW5jb2RpbmcgPSAndXRmOCdcblxuICAvLyBBc3N1bXB0aW9uOiBieXRlTGVuZ3RoKCkgcmV0dXJuIHZhbHVlIGlzIGFsd2F5cyA8IGtNYXhMZW5ndGguXG4gIHZhciBsZW5ndGggPSBieXRlTGVuZ3RoKHN0cmluZywgZW5jb2RpbmcpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuXG4gIHRoYXQud3JpdGUoc3RyaW5nLCBlbmNvZGluZylcbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbU9iamVjdCAodGhhdCwgb2JqZWN0KSB7XG4gIGlmIChCdWZmZXIuaXNCdWZmZXIob2JqZWN0KSkgcmV0dXJuIGZyb21CdWZmZXIodGhhdCwgb2JqZWN0KVxuXG4gIGlmIChpc0FycmF5KG9iamVjdCkpIHJldHVybiBmcm9tQXJyYXkodGhhdCwgb2JqZWN0KVxuXG4gIGlmIChvYmplY3QgPT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ211c3Qgc3RhcnQgd2l0aCBudW1iZXIsIGJ1ZmZlciwgYXJyYXkgb3Igc3RyaW5nJylcbiAgfVxuXG4gIGlmICh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgaWYgKG9iamVjdC5idWZmZXIgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikge1xuICAgICAgcmV0dXJuIGZyb21UeXBlZEFycmF5KHRoYXQsIG9iamVjdClcbiAgICB9XG4gICAgaWYgKG9iamVjdCBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgICByZXR1cm4gZnJvbUFycmF5QnVmZmVyKHRoYXQsIG9iamVjdClcbiAgICB9XG4gIH1cblxuICBpZiAob2JqZWN0Lmxlbmd0aCkgcmV0dXJuIGZyb21BcnJheUxpa2UodGhhdCwgb2JqZWN0KVxuXG4gIHJldHVybiBmcm9tSnNvbk9iamVjdCh0aGF0LCBvYmplY3QpXG59XG5cbmZ1bmN0aW9uIGZyb21CdWZmZXIgKHRoYXQsIGJ1ZmZlcikge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChidWZmZXIubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcbiAgYnVmZmVyLmNvcHkodGhhdCwgMCwgMCwgbGVuZ3RoKVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXkgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vLyBEdXBsaWNhdGUgb2YgZnJvbUFycmF5KCkgdG8ga2VlcCBmcm9tQXJyYXkoKSBtb25vbW9ycGhpYy5cbmZ1bmN0aW9uIGZyb21UeXBlZEFycmF5ICh0aGF0LCBhcnJheSkge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICAvLyBUcnVuY2F0aW5nIHRoZSBlbGVtZW50cyBpcyBwcm9iYWJseSBub3Qgd2hhdCBwZW9wbGUgZXhwZWN0IGZyb20gdHlwZWRcbiAgLy8gYXJyYXlzIHdpdGggQllURVNfUEVSX0VMRU1FTlQgPiAxIGJ1dCBpdCdzIGNvbXBhdGlibGUgd2l0aCB0aGUgYmVoYXZpb3JcbiAgLy8gb2YgdGhlIG9sZCBCdWZmZXIgY29uc3RydWN0b3IuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlCdWZmZXIgKHRoYXQsIGFycmF5KSB7XG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIFJldHVybiBhbiBhdWdtZW50ZWQgYFVpbnQ4QXJyYXlgIGluc3RhbmNlLCBmb3IgYmVzdCBwZXJmb3JtYW5jZVxuICAgIGFycmF5LmJ5dGVMZW5ndGhcbiAgICB0aGF0ID0gQnVmZmVyLl9hdWdtZW50KG5ldyBVaW50OEFycmF5KGFycmF5KSlcbiAgfSBlbHNlIHtcbiAgICAvLyBGYWxsYmFjazogUmV0dXJuIGFuIG9iamVjdCBpbnN0YW5jZSBvZiB0aGUgQnVmZmVyIGNsYXNzXG4gICAgdGhhdCA9IGZyb21UeXBlZEFycmF5KHRoYXQsIG5ldyBVaW50OEFycmF5KGFycmF5KSlcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlMaWtlICh0aGF0LCBhcnJheSkge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuLy8gRGVzZXJpYWxpemUgeyB0eXBlOiAnQnVmZmVyJywgZGF0YTogWzEsMiwzLC4uLl0gfSBpbnRvIGEgQnVmZmVyIG9iamVjdC5cbi8vIFJldHVybnMgYSB6ZXJvLWxlbmd0aCBidWZmZXIgZm9yIGlucHV0cyB0aGF0IGRvbid0IGNvbmZvcm0gdG8gdGhlIHNwZWMuXG5mdW5jdGlvbiBmcm9tSnNvbk9iamVjdCAodGhhdCwgb2JqZWN0KSB7XG4gIHZhciBhcnJheVxuICB2YXIgbGVuZ3RoID0gMFxuXG4gIGlmIChvYmplY3QudHlwZSA9PT0gJ0J1ZmZlcicgJiYgaXNBcnJheShvYmplY3QuZGF0YSkpIHtcbiAgICBhcnJheSA9IG9iamVjdC5kYXRhXG4gICAgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB9XG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICBCdWZmZXIucHJvdG90eXBlLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXkucHJvdG90eXBlXG4gIEJ1ZmZlci5fX3Byb3RvX18gPSBVaW50OEFycmF5XG59XG5cbmZ1bmN0aW9uIGFsbG9jYXRlICh0aGF0LCBsZW5ndGgpIHtcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgdGhhdCA9IEJ1ZmZlci5fYXVnbWVudChuZXcgVWludDhBcnJheShsZW5ndGgpKVxuICAgIHRoYXQuX19wcm90b19fID0gQnVmZmVyLnByb3RvdHlwZVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0Lmxlbmd0aCA9IGxlbmd0aFxuICAgIHRoYXQuX2lzQnVmZmVyID0gdHJ1ZVxuICB9XG5cbiAgdmFyIGZyb21Qb29sID0gbGVuZ3RoICE9PSAwICYmIGxlbmd0aCA8PSBCdWZmZXIucG9vbFNpemUgPj4+IDFcbiAgaWYgKGZyb21Qb29sKSB0aGF0LnBhcmVudCA9IHJvb3RQYXJlbnRcblxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBjaGVja2VkIChsZW5ndGgpIHtcbiAgLy8gTm90ZTogY2Fubm90IHVzZSBgbGVuZ3RoIDwga01heExlbmd0aGAgaGVyZSBiZWNhdXNlIHRoYXQgZmFpbHMgd2hlblxuICAvLyBsZW5ndGggaXMgTmFOICh3aGljaCBpcyBvdGhlcndpc2UgY29lcmNlZCB0byB6ZXJvLilcbiAgaWYgKGxlbmd0aCA+PSBrTWF4TGVuZ3RoKCkpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignQXR0ZW1wdCB0byBhbGxvY2F0ZSBCdWZmZXIgbGFyZ2VyIHRoYW4gbWF4aW11bSAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAnc2l6ZTogMHgnICsga01heExlbmd0aCgpLnRvU3RyaW5nKDE2KSArICcgYnl0ZXMnKVxuICB9XG4gIHJldHVybiBsZW5ndGggfCAwXG59XG5cbmZ1bmN0aW9uIFNsb3dCdWZmZXIgKHN1YmplY3QsIGVuY29kaW5nKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBTbG93QnVmZmVyKSkgcmV0dXJuIG5ldyBTbG93QnVmZmVyKHN1YmplY3QsIGVuY29kaW5nKVxuXG4gIHZhciBidWYgPSBuZXcgQnVmZmVyKHN1YmplY3QsIGVuY29kaW5nKVxuICBkZWxldGUgYnVmLnBhcmVudFxuICByZXR1cm4gYnVmXG59XG5cbkJ1ZmZlci5pc0J1ZmZlciA9IGZ1bmN0aW9uIGlzQnVmZmVyIChiKSB7XG4gIHJldHVybiAhIShiICE9IG51bGwgJiYgYi5faXNCdWZmZXIpXG59XG5cbkJ1ZmZlci5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYSwgYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihhKSB8fCAhQnVmZmVyLmlzQnVmZmVyKGIpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnRzIG11c3QgYmUgQnVmZmVycycpXG4gIH1cblxuICBpZiAoYSA9PT0gYikgcmV0dXJuIDBcblxuICB2YXIgeCA9IGEubGVuZ3RoXG4gIHZhciB5ID0gYi5sZW5ndGhcblxuICB2YXIgaSA9IDBcbiAgdmFyIGxlbiA9IE1hdGgubWluKHgsIHkpXG4gIHdoaWxlIChpIDwgbGVuKSB7XG4gICAgaWYgKGFbaV0gIT09IGJbaV0pIGJyZWFrXG5cbiAgICArK2lcbiAgfVxuXG4gIGlmIChpICE9PSBsZW4pIHtcbiAgICB4ID0gYVtpXVxuICAgIHkgPSBiW2ldXG4gIH1cblxuICBpZiAoeCA8IHkpIHJldHVybiAtMVxuICBpZiAoeSA8IHgpIHJldHVybiAxXG4gIHJldHVybiAwXG59XG5cbkJ1ZmZlci5pc0VuY29kaW5nID0gZnVuY3Rpb24gaXNFbmNvZGluZyAoZW5jb2RpbmcpIHtcbiAgc3dpdGNoIChTdHJpbmcoZW5jb2RpbmcpLnRvTG93ZXJDYXNlKCkpIHtcbiAgICBjYXNlICdoZXgnOlxuICAgIGNhc2UgJ3V0ZjgnOlxuICAgIGNhc2UgJ3V0Zi04JzpcbiAgICBjYXNlICdhc2NpaSc6XG4gICAgY2FzZSAnYmluYXJ5JzpcbiAgICBjYXNlICdiYXNlNjQnOlxuICAgIGNhc2UgJ3Jhdyc6XG4gICAgY2FzZSAndWNzMic6XG4gICAgY2FzZSAndWNzLTInOlxuICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgIHJldHVybiB0cnVlXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbkJ1ZmZlci5jb25jYXQgPSBmdW5jdGlvbiBjb25jYXQgKGxpc3QsIGxlbmd0aCkge1xuICBpZiAoIWlzQXJyYXkobGlzdCkpIHRocm93IG5ldyBUeXBlRXJyb3IoJ2xpc3QgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzLicpXG5cbiAgaWYgKGxpc3QubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIG5ldyBCdWZmZXIoMClcbiAgfVxuXG4gIHZhciBpXG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCkge1xuICAgIGxlbmd0aCA9IDBcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykge1xuICAgICAgbGVuZ3RoICs9IGxpc3RbaV0ubGVuZ3RoXG4gICAgfVxuICB9XG5cbiAgdmFyIGJ1ZiA9IG5ldyBCdWZmZXIobGVuZ3RoKVxuICB2YXIgcG9zID0gMFxuICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykge1xuICAgIHZhciBpdGVtID0gbGlzdFtpXVxuICAgIGl0ZW0uY29weShidWYsIHBvcylcbiAgICBwb3MgKz0gaXRlbS5sZW5ndGhcbiAgfVxuICByZXR1cm4gYnVmXG59XG5cbmZ1bmN0aW9uIGJ5dGVMZW5ndGggKHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBzdHJpbmcgIT09ICdzdHJpbmcnKSBzdHJpbmcgPSAnJyArIHN0cmluZ1xuXG4gIHZhciBsZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChsZW4gPT09IDApIHJldHVybiAwXG5cbiAgLy8gVXNlIGEgZm9yIGxvb3AgdG8gYXZvaWQgcmVjdXJzaW9uXG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG4gIGZvciAoOzspIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgLy8gRGVwcmVjYXRlZFxuICAgICAgY2FzZSAncmF3JzpcbiAgICAgIGNhc2UgJ3Jhd3MnOlxuICAgICAgICByZXR1cm4gbGVuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhUb0J5dGVzKHN0cmluZykubGVuZ3RoXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gbGVuICogMlxuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGxlbiA+Pj4gMVxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGhcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgcmV0dXJuIHV0ZjhUb0J5dGVzKHN0cmluZykubGVuZ3RoIC8vIGFzc3VtZSB1dGY4XG4gICAgICAgIGVuY29kaW5nID0gKCcnICsgZW5jb2RpbmcpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5CdWZmZXIuYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGhcblxuLy8gcHJlLXNldCBmb3IgdmFsdWVzIHRoYXQgbWF5IGV4aXN0IGluIHRoZSBmdXR1cmVcbkJ1ZmZlci5wcm90b3R5cGUubGVuZ3RoID0gdW5kZWZpbmVkXG5CdWZmZXIucHJvdG90eXBlLnBhcmVudCA9IHVuZGVmaW5lZFxuXG5mdW5jdGlvbiBzbG93VG9TdHJpbmcgKGVuY29kaW5nLCBzdGFydCwgZW5kKSB7XG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG5cbiAgc3RhcnQgPSBzdGFydCB8IDBcbiAgZW5kID0gZW5kID09PSB1bmRlZmluZWQgfHwgZW5kID09PSBJbmZpbml0eSA/IHRoaXMubGVuZ3RoIDogZW5kIHwgMFxuXG4gIGlmICghZW5jb2RpbmcpIGVuY29kaW5nID0gJ3V0ZjgnXG4gIGlmIChzdGFydCA8IDApIHN0YXJ0ID0gMFxuICBpZiAoZW5kID4gdGhpcy5sZW5ndGgpIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmIChlbmQgPD0gc3RhcnQpIHJldHVybiAnJ1xuXG4gIHdoaWxlICh0cnVlKSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGhleFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgICAgcmV0dXJuIGFzY2lpU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgICAgcmV0dXJuIGJpbmFyeVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIHJldHVybiBiYXNlNjRTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gdXRmMTZsZVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgICAgICBlbmNvZGluZyA9IChlbmNvZGluZyArICcnKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gdG9TdHJpbmcgKCkge1xuICB2YXIgbGVuZ3RoID0gdGhpcy5sZW5ndGggfCAwXG4gIGlmIChsZW5ndGggPT09IDApIHJldHVybiAnJ1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCAwLCBsZW5ndGgpXG4gIHJldHVybiBzbG93VG9TdHJpbmcuYXBwbHkodGhpcywgYXJndW1lbnRzKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uIGVxdWFscyAoYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpXG4gIGlmICh0aGlzID09PSBiKSByZXR1cm4gdHJ1ZVxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYikgPT09IDBcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbnNwZWN0ID0gZnVuY3Rpb24gaW5zcGVjdCAoKSB7XG4gIHZhciBzdHIgPSAnJ1xuICB2YXIgbWF4ID0gZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFU1xuICBpZiAodGhpcy5sZW5ndGggPiAwKSB7XG4gICAgc3RyID0gdGhpcy50b1N0cmluZygnaGV4JywgMCwgbWF4KS5tYXRjaCgvLnsyfS9nKS5qb2luKCcgJylcbiAgICBpZiAodGhpcy5sZW5ndGggPiBtYXgpIHN0ciArPSAnIC4uLiAnXG4gIH1cbiAgcmV0dXJuICc8QnVmZmVyICcgKyBzdHIgKyAnPidcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpXG4gIGlmICh0aGlzID09PSBiKSByZXR1cm4gMFxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYilcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbmRleE9mID0gZnVuY3Rpb24gaW5kZXhPZiAodmFsLCBieXRlT2Zmc2V0KSB7XG4gIGlmIChieXRlT2Zmc2V0ID4gMHg3ZmZmZmZmZikgYnl0ZU9mZnNldCA9IDB4N2ZmZmZmZmZcbiAgZWxzZSBpZiAoYnl0ZU9mZnNldCA8IC0weDgwMDAwMDAwKSBieXRlT2Zmc2V0ID0gLTB4ODAwMDAwMDBcbiAgYnl0ZU9mZnNldCA+Pj0gMFxuXG4gIGlmICh0aGlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xXG4gIGlmIChieXRlT2Zmc2V0ID49IHRoaXMubGVuZ3RoKSByZXR1cm4gLTFcblxuICAvLyBOZWdhdGl2ZSBvZmZzZXRzIHN0YXJ0IGZyb20gdGhlIGVuZCBvZiB0aGUgYnVmZmVyXG4gIGlmIChieXRlT2Zmc2V0IDwgMCkgYnl0ZU9mZnNldCA9IE1hdGgubWF4KHRoaXMubGVuZ3RoICsgYnl0ZU9mZnNldCwgMClcblxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICBpZiAodmFsLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xIC8vIHNwZWNpYWwgY2FzZTogbG9va2luZyBmb3IgZW1wdHkgc3RyaW5nIGFsd2F5cyBmYWlsc1xuICAgIHJldHVybiBTdHJpbmcucHJvdG90eXBlLmluZGV4T2YuY2FsbCh0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gIH1cbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcih2YWwpKSB7XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gIH1cbiAgaWYgKHR5cGVvZiB2YWwgPT09ICdudW1iZXInKSB7XG4gICAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUICYmIFVpbnQ4QXJyYXkucHJvdG90eXBlLmluZGV4T2YgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHJldHVybiBVaW50OEFycmF5LnByb3RvdHlwZS5pbmRleE9mLmNhbGwodGhpcywgdmFsLCBieXRlT2Zmc2V0KVxuICAgIH1cbiAgICByZXR1cm4gYXJyYXlJbmRleE9mKHRoaXMsIFsgdmFsIF0sIGJ5dGVPZmZzZXQpXG4gIH1cblxuICBmdW5jdGlvbiBhcnJheUluZGV4T2YgKGFyciwgdmFsLCBieXRlT2Zmc2V0KSB7XG4gICAgdmFyIGZvdW5kSW5kZXggPSAtMVxuICAgIGZvciAodmFyIGkgPSAwOyBieXRlT2Zmc2V0ICsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGFycltieXRlT2Zmc2V0ICsgaV0gPT09IHZhbFtmb3VuZEluZGV4ID09PSAtMSA/IDAgOiBpIC0gZm91bmRJbmRleF0pIHtcbiAgICAgICAgaWYgKGZvdW5kSW5kZXggPT09IC0xKSBmb3VuZEluZGV4ID0gaVxuICAgICAgICBpZiAoaSAtIGZvdW5kSW5kZXggKyAxID09PSB2YWwubGVuZ3RoKSByZXR1cm4gYnl0ZU9mZnNldCArIGZvdW5kSW5kZXhcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvdW5kSW5kZXggPSAtMVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gLTFcbiAgfVxuXG4gIHRocm93IG5ldyBUeXBlRXJyb3IoJ3ZhbCBtdXN0IGJlIHN0cmluZywgbnVtYmVyIG9yIEJ1ZmZlcicpXG59XG5cbi8vIGBnZXRgIGlzIGRlcHJlY2F0ZWRcbkJ1ZmZlci5wcm90b3R5cGUuZ2V0ID0gZnVuY3Rpb24gZ2V0IChvZmZzZXQpIHtcbiAgY29uc29sZS5sb2coJy5nZXQoKSBpcyBkZXByZWNhdGVkLiBBY2Nlc3MgdXNpbmcgYXJyYXkgaW5kZXhlcyBpbnN0ZWFkLicpXG4gIHJldHVybiB0aGlzLnJlYWRVSW50OChvZmZzZXQpXG59XG5cbi8vIGBzZXRgIGlzIGRlcHJlY2F0ZWRcbkJ1ZmZlci5wcm90b3R5cGUuc2V0ID0gZnVuY3Rpb24gc2V0ICh2LCBvZmZzZXQpIHtcbiAgY29uc29sZS5sb2coJy5zZXQoKSBpcyBkZXByZWNhdGVkLiBBY2Nlc3MgdXNpbmcgYXJyYXkgaW5kZXhlcyBpbnN0ZWFkLicpXG4gIHJldHVybiB0aGlzLndyaXRlVUludDgodiwgb2Zmc2V0KVxufVxuXG5mdW5jdGlvbiBoZXhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIG9mZnNldCA9IE51bWJlcihvZmZzZXQpIHx8IDBcbiAgdmFyIHJlbWFpbmluZyA9IGJ1Zi5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKCFsZW5ndGgpIHtcbiAgICBsZW5ndGggPSByZW1haW5pbmdcbiAgfSBlbHNlIHtcbiAgICBsZW5ndGggPSBOdW1iZXIobGVuZ3RoKVxuICAgIGlmIChsZW5ndGggPiByZW1haW5pbmcpIHtcbiAgICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICAgIH1cbiAgfVxuXG4gIC8vIG11c3QgYmUgYW4gZXZlbiBudW1iZXIgb2YgZGlnaXRzXG4gIHZhciBzdHJMZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChzdHJMZW4gJSAyICE9PSAwKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGV4IHN0cmluZycpXG5cbiAgaWYgKGxlbmd0aCA+IHN0ckxlbiAvIDIpIHtcbiAgICBsZW5ndGggPSBzdHJMZW4gLyAyXG4gIH1cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIHZhciBwYXJzZWQgPSBwYXJzZUludChzdHJpbmcuc3Vic3RyKGkgKiAyLCAyKSwgMTYpXG4gICAgaWYgKGlzTmFOKHBhcnNlZCkpIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSBwYXJzZWRcbiAgfVxuICByZXR1cm4gaVxufVxuXG5mdW5jdGlvbiB1dGY4V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcih1dGY4VG9CeXRlcyhzdHJpbmcsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBhc2NpaVdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIoYXNjaWlUb0J5dGVzKHN0cmluZyksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGJpbmFyeVdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGFzY2lpV3JpdGUoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBiYXNlNjRXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKGJhc2U2NFRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gdWNzMldyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIodXRmMTZsZVRvQnl0ZXMoc3RyaW5nLCBidWYubGVuZ3RoIC0gb2Zmc2V0KSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZSA9IGZ1bmN0aW9uIHdyaXRlIChzdHJpbmcsIG9mZnNldCwgbGVuZ3RoLCBlbmNvZGluZykge1xuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nKVxuICBpZiAob2Zmc2V0ID09PSB1bmRlZmluZWQpIHtcbiAgICBlbmNvZGluZyA9ICd1dGY4J1xuICAgIGxlbmd0aCA9IHRoaXMubGVuZ3RoXG4gICAgb2Zmc2V0ID0gMFxuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nLCBlbmNvZGluZylcbiAgfSBlbHNlIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygb2Zmc2V0ID09PSAnc3RyaW5nJykge1xuICAgIGVuY29kaW5nID0gb2Zmc2V0XG4gICAgbGVuZ3RoID0gdGhpcy5sZW5ndGhcbiAgICBvZmZzZXQgPSAwXG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcsIG9mZnNldFssIGxlbmd0aF1bLCBlbmNvZGluZ10pXG4gIH0gZWxzZSBpZiAoaXNGaW5pdGUob2Zmc2V0KSkge1xuICAgIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgICBpZiAoaXNGaW5pdGUobGVuZ3RoKSkge1xuICAgICAgbGVuZ3RoID0gbGVuZ3RoIHwgMFxuICAgICAgaWYgKGVuY29kaW5nID09PSB1bmRlZmluZWQpIGVuY29kaW5nID0gJ3V0ZjgnXG4gICAgfSBlbHNlIHtcbiAgICAgIGVuY29kaW5nID0gbGVuZ3RoXG4gICAgICBsZW5ndGggPSB1bmRlZmluZWRcbiAgICB9XG4gIC8vIGxlZ2FjeSB3cml0ZShzdHJpbmcsIGVuY29kaW5nLCBvZmZzZXQsIGxlbmd0aCkgLSByZW1vdmUgaW4gdjAuMTNcbiAgfSBlbHNlIHtcbiAgICB2YXIgc3dhcCA9IGVuY29kaW5nXG4gICAgZW5jb2RpbmcgPSBvZmZzZXRcbiAgICBvZmZzZXQgPSBsZW5ndGggfCAwXG4gICAgbGVuZ3RoID0gc3dhcFxuICB9XG5cbiAgdmFyIHJlbWFpbmluZyA9IHRoaXMubGVuZ3RoIC0gb2Zmc2V0XG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCB8fCBsZW5ndGggPiByZW1haW5pbmcpIGxlbmd0aCA9IHJlbWFpbmluZ1xuXG4gIGlmICgoc3RyaW5nLmxlbmd0aCA+IDAgJiYgKGxlbmd0aCA8IDAgfHwgb2Zmc2V0IDwgMCkpIHx8IG9mZnNldCA+IHRoaXMubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2F0dGVtcHQgdG8gd3JpdGUgb3V0c2lkZSBidWZmZXIgYm91bmRzJylcbiAgfVxuXG4gIGlmICghZW5jb2RpbmcpIGVuY29kaW5nID0gJ3V0ZjgnXG5cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBoZXhXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICAgIHJldHVybiBhc2NpaVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAgIHJldHVybiBiaW5hcnlXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICAvLyBXYXJuaW5nOiBtYXhMZW5ndGggbm90IHRha2VuIGludG8gYWNjb3VudCBpbiBiYXNlNjRXcml0ZVxuICAgICAgICByZXR1cm4gYmFzZTY0V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIHVjczJXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBlbmNvZGluZylcbiAgICAgICAgZW5jb2RpbmcgPSAoJycgKyBlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS50b0pTT04gPSBmdW5jdGlvbiB0b0pTT04gKCkge1xuICByZXR1cm4ge1xuICAgIHR5cGU6ICdCdWZmZXInLFxuICAgIGRhdGE6IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHRoaXMuX2FyciB8fCB0aGlzLCAwKVxuICB9XG59XG5cbmZ1bmN0aW9uIGJhc2U2NFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgaWYgKHN0YXJ0ID09PSAwICYmIGVuZCA9PT0gYnVmLmxlbmd0aCkge1xuICAgIHJldHVybiBiYXNlNjQuZnJvbUJ5dGVBcnJheShidWYpXG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIGJhc2U2NC5mcm9tQnl0ZUFycmF5KGJ1Zi5zbGljZShzdGFydCwgZW5kKSlcbiAgfVxufVxuXG5mdW5jdGlvbiB1dGY4U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG4gIHZhciByZXMgPSBbXVxuXG4gIHZhciBpID0gc3RhcnRcbiAgd2hpbGUgKGkgPCBlbmQpIHtcbiAgICB2YXIgZmlyc3RCeXRlID0gYnVmW2ldXG4gICAgdmFyIGNvZGVQb2ludCA9IG51bGxcbiAgICB2YXIgYnl0ZXNQZXJTZXF1ZW5jZSA9IChmaXJzdEJ5dGUgPiAweEVGKSA/IDRcbiAgICAgIDogKGZpcnN0Qnl0ZSA+IDB4REYpID8gM1xuICAgICAgOiAoZmlyc3RCeXRlID4gMHhCRikgPyAyXG4gICAgICA6IDFcblxuICAgIGlmIChpICsgYnl0ZXNQZXJTZXF1ZW5jZSA8PSBlbmQpIHtcbiAgICAgIHZhciBzZWNvbmRCeXRlLCB0aGlyZEJ5dGUsIGZvdXJ0aEJ5dGUsIHRlbXBDb2RlUG9pbnRcblxuICAgICAgc3dpdGNoIChieXRlc1BlclNlcXVlbmNlKSB7XG4gICAgICAgIGNhc2UgMTpcbiAgICAgICAgICBpZiAoZmlyc3RCeXRlIDwgMHg4MCkge1xuICAgICAgICAgICAgY29kZVBvaW50ID0gZmlyc3RCeXRlXG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgMjpcbiAgICAgICAgICBzZWNvbmRCeXRlID0gYnVmW2kgKyAxXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4MUYpIDw8IDB4NiB8IChzZWNvbmRCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHg3Rikge1xuICAgICAgICAgICAgICBjb2RlUG9pbnQgPSB0ZW1wQ29kZVBvaW50XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgMzpcbiAgICAgICAgICBzZWNvbmRCeXRlID0gYnVmW2kgKyAxXVxuICAgICAgICAgIHRoaXJkQnl0ZSA9IGJ1ZltpICsgMl1cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAodGhpcmRCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHhGKSA8PCAweEMgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpIDw8IDB4NiB8ICh0aGlyZEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweDdGRiAmJiAodGVtcENvZGVQb2ludCA8IDB4RDgwMCB8fCB0ZW1wQ29kZVBvaW50ID4gMHhERkZGKSkge1xuICAgICAgICAgICAgICBjb2RlUG9pbnQgPSB0ZW1wQ29kZVBvaW50XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgNDpcbiAgICAgICAgICBzZWNvbmRCeXRlID0gYnVmW2kgKyAxXVxuICAgICAgICAgIHRoaXJkQnl0ZSA9IGJ1ZltpICsgMl1cbiAgICAgICAgICBmb3VydGhCeXRlID0gYnVmW2kgKyAzXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwICYmICh0aGlyZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAoZm91cnRoQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4RikgPDwgMHgxMiB8IChzZWNvbmRCeXRlICYgMHgzRikgPDwgMHhDIHwgKHRoaXJkQnl0ZSAmIDB4M0YpIDw8IDB4NiB8IChmb3VydGhCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHhGRkZGICYmIHRlbXBDb2RlUG9pbnQgPCAweDExMDAwMCkge1xuICAgICAgICAgICAgICBjb2RlUG9pbnQgPSB0ZW1wQ29kZVBvaW50XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChjb2RlUG9pbnQgPT09IG51bGwpIHtcbiAgICAgIC8vIHdlIGRpZCBub3QgZ2VuZXJhdGUgYSB2YWxpZCBjb2RlUG9pbnQgc28gaW5zZXJ0IGFcbiAgICAgIC8vIHJlcGxhY2VtZW50IGNoYXIgKFUrRkZGRCkgYW5kIGFkdmFuY2Ugb25seSAxIGJ5dGVcbiAgICAgIGNvZGVQb2ludCA9IDB4RkZGRFxuICAgICAgYnl0ZXNQZXJTZXF1ZW5jZSA9IDFcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA+IDB4RkZGRikge1xuICAgICAgLy8gZW5jb2RlIHRvIHV0ZjE2IChzdXJyb2dhdGUgcGFpciBkYW5jZSlcbiAgICAgIGNvZGVQb2ludCAtPSAweDEwMDAwXG4gICAgICByZXMucHVzaChjb2RlUG9pbnQgPj4+IDEwICYgMHgzRkYgfCAweEQ4MDApXG4gICAgICBjb2RlUG9pbnQgPSAweERDMDAgfCBjb2RlUG9pbnQgJiAweDNGRlxuICAgIH1cblxuICAgIHJlcy5wdXNoKGNvZGVQb2ludClcbiAgICBpICs9IGJ5dGVzUGVyU2VxdWVuY2VcbiAgfVxuXG4gIHJldHVybiBkZWNvZGVDb2RlUG9pbnRzQXJyYXkocmVzKVxufVxuXG4vLyBCYXNlZCBvbiBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8yMjc0NzI3Mi82ODA3NDIsIHRoZSBicm93c2VyIHdpdGhcbi8vIHRoZSBsb3dlc3QgbGltaXQgaXMgQ2hyb21lLCB3aXRoIDB4MTAwMDAgYXJncy5cbi8vIFdlIGdvIDEgbWFnbml0dWRlIGxlc3MsIGZvciBzYWZldHlcbnZhciBNQVhfQVJHVU1FTlRTX0xFTkdUSCA9IDB4MTAwMFxuXG5mdW5jdGlvbiBkZWNvZGVDb2RlUG9pbnRzQXJyYXkgKGNvZGVQb2ludHMpIHtcbiAgdmFyIGxlbiA9IGNvZGVQb2ludHMubGVuZ3RoXG4gIGlmIChsZW4gPD0gTUFYX0FSR1VNRU5UU19MRU5HVEgpIHtcbiAgICByZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShTdHJpbmcsIGNvZGVQb2ludHMpIC8vIGF2b2lkIGV4dHJhIHNsaWNlKClcbiAgfVxuXG4gIC8vIERlY29kZSBpbiBjaHVua3MgdG8gYXZvaWQgXCJjYWxsIHN0YWNrIHNpemUgZXhjZWVkZWRcIi5cbiAgdmFyIHJlcyA9ICcnXG4gIHZhciBpID0gMFxuICB3aGlsZSAoaSA8IGxlbikge1xuICAgIHJlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFxuICAgICAgU3RyaW5nLFxuICAgICAgY29kZVBvaW50cy5zbGljZShpLCBpICs9IE1BWF9BUkdVTUVOVFNfTEVOR1RIKVxuICAgIClcbiAgfVxuICByZXR1cm4gcmVzXG59XG5cbmZ1bmN0aW9uIGFzY2lpU2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgcmV0ID0gJydcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgcmV0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnVmW2ldICYgMHg3RilcbiAgfVxuICByZXR1cm4gcmV0XG59XG5cbmZ1bmN0aW9uIGJpbmFyeVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIHJldCA9ICcnXG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcblxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIHJldCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ1ZltpXSlcbiAgfVxuICByZXR1cm4gcmV0XG59XG5cbmZ1bmN0aW9uIGhleFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxlbiA9IGJ1Zi5sZW5ndGhcblxuICBpZiAoIXN0YXJ0IHx8IHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIGlmICghZW5kIHx8IGVuZCA8IDAgfHwgZW5kID4gbGVuKSBlbmQgPSBsZW5cblxuICB2YXIgb3V0ID0gJydcbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICBvdXQgKz0gdG9IZXgoYnVmW2ldKVxuICB9XG4gIHJldHVybiBvdXRcbn1cblxuZnVuY3Rpb24gdXRmMTZsZVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGJ5dGVzID0gYnVmLnNsaWNlKHN0YXJ0LCBlbmQpXG4gIHZhciByZXMgPSAnJ1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSArPSAyKSB7XG4gICAgcmVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnl0ZXNbaV0gKyBieXRlc1tpICsgMV0gKiAyNTYpXG4gIH1cbiAgcmV0dXJuIHJlc1xufVxuXG5CdWZmZXIucHJvdG90eXBlLnNsaWNlID0gZnVuY3Rpb24gc2xpY2UgKHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxlbiA9IHRoaXMubGVuZ3RoXG4gIHN0YXJ0ID0gfn5zdGFydFxuICBlbmQgPSBlbmQgPT09IHVuZGVmaW5lZCA/IGxlbiA6IH5+ZW5kXG5cbiAgaWYgKHN0YXJ0IDwgMCkge1xuICAgIHN0YXJ0ICs9IGxlblxuICAgIGlmIChzdGFydCA8IDApIHN0YXJ0ID0gMFxuICB9IGVsc2UgaWYgKHN0YXJ0ID4gbGVuKSB7XG4gICAgc3RhcnQgPSBsZW5cbiAgfVxuXG4gIGlmIChlbmQgPCAwKSB7XG4gICAgZW5kICs9IGxlblxuICAgIGlmIChlbmQgPCAwKSBlbmQgPSAwXG4gIH0gZWxzZSBpZiAoZW5kID4gbGVuKSB7XG4gICAgZW5kID0gbGVuXG4gIH1cblxuICBpZiAoZW5kIDwgc3RhcnQpIGVuZCA9IHN0YXJ0XG5cbiAgdmFyIG5ld0J1ZlxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICBuZXdCdWYgPSBCdWZmZXIuX2F1Z21lbnQodGhpcy5zdWJhcnJheShzdGFydCwgZW5kKSlcbiAgfSBlbHNlIHtcbiAgICB2YXIgc2xpY2VMZW4gPSBlbmQgLSBzdGFydFxuICAgIG5ld0J1ZiA9IG5ldyBCdWZmZXIoc2xpY2VMZW4sIHVuZGVmaW5lZClcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNsaWNlTGVuOyBpKyspIHtcbiAgICAgIG5ld0J1ZltpXSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfVxuXG4gIGlmIChuZXdCdWYubGVuZ3RoKSBuZXdCdWYucGFyZW50ID0gdGhpcy5wYXJlbnQgfHwgdGhpc1xuXG4gIHJldHVybiBuZXdCdWZcbn1cblxuLypcbiAqIE5lZWQgdG8gbWFrZSBzdXJlIHRoYXQgYnVmZmVyIGlzbid0IHRyeWluZyB0byB3cml0ZSBvdXQgb2YgYm91bmRzLlxuICovXG5mdW5jdGlvbiBjaGVja09mZnNldCAob2Zmc2V0LCBleHQsIGxlbmd0aCkge1xuICBpZiAoKG9mZnNldCAlIDEpICE9PSAwIHx8IG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdvZmZzZXQgaXMgbm90IHVpbnQnKVxuICBpZiAob2Zmc2V0ICsgZXh0ID4gbGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignVHJ5aW5nIHRvIGFjY2VzcyBiZXlvbmQgYnVmZmVyIGxlbmd0aCcpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnRMRSA9IGZ1bmN0aW9uIHJlYWRVSW50TEUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIGldICogbXVsXG4gIH1cblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnRCRSA9IGZ1bmN0aW9uIHJlYWRVSW50QkUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG4gIH1cblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAtLWJ5dGVMZW5ndGhdXG4gIHZhciBtdWwgPSAxXG4gIHdoaWxlIChieXRlTGVuZ3RoID4gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIC0tYnl0ZUxlbmd0aF0gKiBtdWxcbiAgfVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDggPSBmdW5jdGlvbiByZWFkVUludDggKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAxLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIHRoaXNbb2Zmc2V0XVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MTZMRSA9IGZ1bmN0aW9uIHJlYWRVSW50MTZMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gdGhpc1tvZmZzZXRdIHwgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDE2QkUgPSBmdW5jdGlvbiByZWFkVUludDE2QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuICh0aGlzW29mZnNldF0gPDwgOCkgfCB0aGlzW29mZnNldCArIDFdXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQzMkxFID0gZnVuY3Rpb24gcmVhZFVJbnQzMkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICgodGhpc1tvZmZzZXRdKSB8XG4gICAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KSB8XG4gICAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCAxNikpICtcbiAgICAgICh0aGlzW29mZnNldCArIDNdICogMHgxMDAwMDAwKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MzJCRSA9IGZ1bmN0aW9uIHJlYWRVSW50MzJCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAodGhpc1tvZmZzZXRdICogMHgxMDAwMDAwKSArXG4gICAgKCh0aGlzW29mZnNldCArIDFdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgOCkgfFxuICAgIHRoaXNbb2Zmc2V0ICsgM10pXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludExFID0gZnVuY3Rpb24gcmVhZEludExFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XVxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyBpXSAqIG11bFxuICB9XG4gIG11bCAqPSAweDgwXG5cbiAgaWYgKHZhbCA+PSBtdWwpIHZhbCAtPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aClcblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludEJFID0gZnVuY3Rpb24gcmVhZEludEJFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIGkgPSBieXRlTGVuZ3RoXG4gIHZhciBtdWwgPSAxXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIC0taV1cbiAgd2hpbGUgKGkgPiAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgLS1pXSAqIG11bFxuICB9XG4gIG11bCAqPSAweDgwXG5cbiAgaWYgKHZhbCA+PSBtdWwpIHZhbCAtPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aClcblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDggPSBmdW5jdGlvbiByZWFkSW50OCAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDEsIHRoaXMubGVuZ3RoKVxuICBpZiAoISh0aGlzW29mZnNldF0gJiAweDgwKSkgcmV0dXJuICh0aGlzW29mZnNldF0pXG4gIHJldHVybiAoKDB4ZmYgLSB0aGlzW29mZnNldF0gKyAxKSAqIC0xKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQxNkxFID0gZnVuY3Rpb24gcmVhZEludDE2TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XSB8ICh0aGlzW29mZnNldCArIDFdIDw8IDgpXG4gIHJldHVybiAodmFsICYgMHg4MDAwKSA/IHZhbCB8IDB4RkZGRjAwMDAgOiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MTZCRSA9IGZ1bmN0aW9uIHJlYWRJbnQxNkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIDFdIHwgKHRoaXNbb2Zmc2V0XSA8PCA4KVxuICByZXR1cm4gKHZhbCAmIDB4ODAwMCkgPyB2YWwgfCAweEZGRkYwMDAwIDogdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDMyTEUgPSBmdW5jdGlvbiByZWFkSW50MzJMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAodGhpc1tvZmZzZXRdKSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOCkgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgM10gPDwgMjQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDMyQkUgPSBmdW5jdGlvbiByZWFkSW50MzJCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAodGhpc1tvZmZzZXRdIDw8IDI0KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCA4KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgM10pXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEZsb2F0TEUgPSBmdW5jdGlvbiByZWFkRmxvYXRMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgdHJ1ZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEZsb2F0QkUgPSBmdW5jdGlvbiByZWFkRmxvYXRCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgZmFsc2UsIDIzLCA0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWREb3VibGVMRSA9IGZ1bmN0aW9uIHJlYWREb3VibGVMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDgsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgdHJ1ZSwgNTIsIDgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUJFID0gZnVuY3Rpb24gcmVhZERvdWJsZUJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgOCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCBmYWxzZSwgNTIsIDgpXG59XG5cbmZ1bmN0aW9uIGNoZWNrSW50IChidWYsIHZhbHVlLCBvZmZzZXQsIGV4dCwgbWF4LCBtaW4pIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoYnVmKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignYnVmZmVyIG11c3QgYmUgYSBCdWZmZXIgaW5zdGFuY2UnKVxuICBpZiAodmFsdWUgPiBtYXggfHwgdmFsdWUgPCBtaW4pIHRocm93IG5ldyBSYW5nZUVycm9yKCd2YWx1ZSBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludExFID0gZnVuY3Rpb24gd3JpdGVVSW50TEUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKSwgMClcblxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludEJFID0gZnVuY3Rpb24gd3JpdGVVSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKSwgMClcblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDggPSBmdW5jdGlvbiB3cml0ZVVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4ZmYsIDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MTYgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgMik7IGkgPCBqOyBpKyspIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgJiAoMHhmZiA8PCAoOCAqIChsaXR0bGVFbmRpYW4gPyBpIDogMSAtIGkpKSkpID4+PlxuICAgICAgKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkgKiA4XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlVUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHhmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MzIgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBmb3IgKHZhciBpID0gMCwgaiA9IE1hdGgubWluKGJ1Zi5sZW5ndGggLSBvZmZzZXQsIDQpOyBpIDwgajsgaSsrKSB7XG4gICAgYnVmW29mZnNldCArIGldID0gKHZhbHVlID4+PiAobGl0dGxlRW5kaWFuID8gaSA6IDMgLSBpKSAqIDgpICYgMHhmZlxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlVUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHhmZmZmZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludExFID0gZnVuY3Rpb24gd3JpdGVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IDBcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHN1YiA9IHZhbHVlIDwgMCA/IDEgOiAwXG4gIHRoaXNbb2Zmc2V0XSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAoKHZhbHVlIC8gbXVsKSA+PiAwKSAtIHN1YiAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnRCRSA9IGZ1bmN0aW9uIHdyaXRlSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIHZhciBsaW1pdCA9IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoIC0gMSlcblxuICAgIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIGxpbWl0IC0gMSwgLWxpbWl0KVxuICB9XG5cbiAgdmFyIGkgPSBieXRlTGVuZ3RoIC0gMVxuICB2YXIgbXVsID0gMVxuICB2YXIgc3ViID0gdmFsdWUgPCAwID8gMSA6IDBcbiAgdGhpc1tvZmZzZXQgKyBpXSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoLS1pID49IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKCh2YWx1ZSAvIG11bCkgPj4gMCkgLSBzdWIgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50OCA9IGZ1bmN0aW9uIHdyaXRlSW50OCAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAxLCAweDdmLCAtMHg4MClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkgdmFsdWUgPSBNYXRoLmZsb29yKHZhbHVlKVxuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmYgKyB2YWx1ZSArIDFcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDE2TEUgPSBmdW5jdGlvbiB3cml0ZUludDE2TEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHg3ZmZmLCAtMHg4MDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlSW50MTZCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweDdmZmYsIC0weDgwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlSW50MzJMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweDdmZmZmZmZmLCAtMHg4MDAwMDAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgPj4+IDI0KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDMyQkUgPSBmdW5jdGlvbiB3cml0ZUludDMyQkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHg3ZmZmZmZmZiwgLTB4ODAwMDAwMDApXG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuZnVuY3Rpb24gY2hlY2tJRUVFNzU0IChidWYsIHZhbHVlLCBvZmZzZXQsIGV4dCwgbWF4LCBtaW4pIHtcbiAgaWYgKHZhbHVlID4gbWF4IHx8IHZhbHVlIDwgbWluKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcigndmFsdWUgaXMgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBidWYubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignaW5kZXggb3V0IG9mIHJhbmdlJylcbiAgaWYgKG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5mdW5jdGlvbiB3cml0ZUZsb2F0IChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDQsIDMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgsIC0zLjQwMjgyMzQ2NjM4NTI4ODZlKzM4KVxuICB9XG4gIGllZWU3NTQud3JpdGUoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4sIDIzLCA0KVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRmxvYXRMRSA9IGZ1bmN0aW9uIHdyaXRlRmxvYXRMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRmxvYXQodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSwgbm9Bc3NlcnQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdEJFID0gZnVuY3Rpb24gd3JpdGVGbG9hdEJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSwgbm9Bc3NlcnQpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRG91YmxlIChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDgsIDEuNzk3NjkzMTM0ODYyMzE1N0UrMzA4LCAtMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgNTIsIDgpXG4gIHJldHVybiBvZmZzZXQgKyA4XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVEb3VibGVMRSA9IGZ1bmN0aW9uIHdyaXRlRG91YmxlTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZURvdWJsZSh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUJFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuLy8gY29weSh0YXJnZXRCdWZmZXIsIHRhcmdldFN0YXJ0PTAsIHNvdXJjZVN0YXJ0PTAsIHNvdXJjZUVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5jb3B5ID0gZnVuY3Rpb24gY29weSAodGFyZ2V0LCB0YXJnZXRTdGFydCwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXN0YXJ0KSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgJiYgZW5kICE9PSAwKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0U3RhcnQgPj0gdGFyZ2V0Lmxlbmd0aCkgdGFyZ2V0U3RhcnQgPSB0YXJnZXQubGVuZ3RoXG4gIGlmICghdGFyZ2V0U3RhcnQpIHRhcmdldFN0YXJ0ID0gMFxuICBpZiAoZW5kID4gMCAmJiBlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICAvLyBDb3B5IDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVybiAwXG4gIGlmICh0YXJnZXQubGVuZ3RoID09PSAwIHx8IHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gMFxuXG4gIC8vIEZhdGFsIGVycm9yIGNvbmRpdGlvbnNcbiAgaWYgKHRhcmdldFN0YXJ0IDwgMCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCd0YXJnZXRTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgfVxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlU3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlRW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIC8vIEFyZSB3ZSBvb2I/XG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKHRhcmdldC5sZW5ndGggLSB0YXJnZXRTdGFydCA8IGVuZCAtIHN0YXJ0KSB7XG4gICAgZW5kID0gdGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0ICsgc3RhcnRcbiAgfVxuXG4gIHZhciBsZW4gPSBlbmQgLSBzdGFydFxuICB2YXIgaVxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQgJiYgc3RhcnQgPCB0YXJnZXRTdGFydCAmJiB0YXJnZXRTdGFydCA8IGVuZCkge1xuICAgIC8vIGRlc2NlbmRpbmcgY29weSBmcm9tIGVuZFxuICAgIGZvciAoaSA9IGxlbiAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICB0YXJnZXRbaSArIHRhcmdldFN0YXJ0XSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfSBlbHNlIGlmIChsZW4gPCAxMDAwIHx8ICFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIGFzY2VuZGluZyBjb3B5IGZyb20gc3RhcnRcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHRhcmdldC5fc2V0KHRoaXMuc3ViYXJyYXkoc3RhcnQsIHN0YXJ0ICsgbGVuKSwgdGFyZ2V0U3RhcnQpXG4gIH1cblxuICByZXR1cm4gbGVuXG59XG5cbi8vIGZpbGwodmFsdWUsIHN0YXJ0PTAsIGVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5maWxsID0gZnVuY3Rpb24gZmlsbCAodmFsdWUsIHN0YXJ0LCBlbmQpIHtcbiAgaWYgKCF2YWx1ZSkgdmFsdWUgPSAwXG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCkgZW5kID0gdGhpcy5sZW5ndGhcblxuICBpZiAoZW5kIDwgc3RhcnQpIHRocm93IG5ldyBSYW5nZUVycm9yKCdlbmQgPCBzdGFydCcpXG5cbiAgLy8gRmlsbCAwIGJ5dGVzOyB3ZSdyZSBkb25lXG4gIGlmIChlbmQgPT09IHN0YXJ0KSByZXR1cm5cbiAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm5cblxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwIHx8IGVuZCA+IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignZW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIHZhciBpXG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdGhpc1tpXSA9IHZhbHVlXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHZhciBieXRlcyA9IHV0ZjhUb0J5dGVzKHZhbHVlLnRvU3RyaW5nKCkpXG4gICAgdmFyIGxlbiA9IGJ5dGVzLmxlbmd0aFxuICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICAgIHRoaXNbaV0gPSBieXRlc1tpICUgbGVuXVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzXG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBgQXJyYXlCdWZmZXJgIHdpdGggdGhlICpjb3BpZWQqIG1lbW9yeSBvZiB0aGUgYnVmZmVyIGluc3RhbmNlLlxuICogQWRkZWQgaW4gTm9kZSAwLjEyLiBPbmx5IGF2YWlsYWJsZSBpbiBicm93c2VycyB0aGF0IHN1cHBvcnQgQXJyYXlCdWZmZXIuXG4gKi9cbkJ1ZmZlci5wcm90b3R5cGUudG9BcnJheUJ1ZmZlciA9IGZ1bmN0aW9uIHRvQXJyYXlCdWZmZXIgKCkge1xuICBpZiAodHlwZW9mIFVpbnQ4QXJyYXkgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgICByZXR1cm4gKG5ldyBCdWZmZXIodGhpcykpLmJ1ZmZlclxuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgYnVmID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5sZW5ndGgpXG4gICAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gYnVmLmxlbmd0aDsgaSA8IGxlbjsgaSArPSAxKSB7XG4gICAgICAgIGJ1ZltpXSA9IHRoaXNbaV1cbiAgICAgIH1cbiAgICAgIHJldHVybiBidWYuYnVmZmVyXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0J1ZmZlci50b0FycmF5QnVmZmVyIG5vdCBzdXBwb3J0ZWQgaW4gdGhpcyBicm93c2VyJylcbiAgfVxufVxuXG4vLyBIRUxQRVIgRlVOQ1RJT05TXG4vLyA9PT09PT09PT09PT09PT09XG5cbnZhciBCUCA9IEJ1ZmZlci5wcm90b3R5cGVcblxuLyoqXG4gKiBBdWdtZW50IGEgVWludDhBcnJheSAqaW5zdGFuY2UqIChub3QgdGhlIFVpbnQ4QXJyYXkgY2xhc3MhKSB3aXRoIEJ1ZmZlciBtZXRob2RzXG4gKi9cbkJ1ZmZlci5fYXVnbWVudCA9IGZ1bmN0aW9uIF9hdWdtZW50IChhcnIpIHtcbiAgYXJyLmNvbnN0cnVjdG9yID0gQnVmZmVyXG4gIGFyci5faXNCdWZmZXIgPSB0cnVlXG5cbiAgLy8gc2F2ZSByZWZlcmVuY2UgdG8gb3JpZ2luYWwgVWludDhBcnJheSBzZXQgbWV0aG9kIGJlZm9yZSBvdmVyd3JpdGluZ1xuICBhcnIuX3NldCA9IGFyci5zZXRcblxuICAvLyBkZXByZWNhdGVkXG4gIGFyci5nZXQgPSBCUC5nZXRcbiAgYXJyLnNldCA9IEJQLnNldFxuXG4gIGFyci53cml0ZSA9IEJQLndyaXRlXG4gIGFyci50b1N0cmluZyA9IEJQLnRvU3RyaW5nXG4gIGFyci50b0xvY2FsZVN0cmluZyA9IEJQLnRvU3RyaW5nXG4gIGFyci50b0pTT04gPSBCUC50b0pTT05cbiAgYXJyLmVxdWFscyA9IEJQLmVxdWFsc1xuICBhcnIuY29tcGFyZSA9IEJQLmNvbXBhcmVcbiAgYXJyLmluZGV4T2YgPSBCUC5pbmRleE9mXG4gIGFyci5jb3B5ID0gQlAuY29weVxuICBhcnIuc2xpY2UgPSBCUC5zbGljZVxuICBhcnIucmVhZFVJbnRMRSA9IEJQLnJlYWRVSW50TEVcbiAgYXJyLnJlYWRVSW50QkUgPSBCUC5yZWFkVUludEJFXG4gIGFyci5yZWFkVUludDggPSBCUC5yZWFkVUludDhcbiAgYXJyLnJlYWRVSW50MTZMRSA9IEJQLnJlYWRVSW50MTZMRVxuICBhcnIucmVhZFVJbnQxNkJFID0gQlAucmVhZFVJbnQxNkJFXG4gIGFyci5yZWFkVUludDMyTEUgPSBCUC5yZWFkVUludDMyTEVcbiAgYXJyLnJlYWRVSW50MzJCRSA9IEJQLnJlYWRVSW50MzJCRVxuICBhcnIucmVhZEludExFID0gQlAucmVhZEludExFXG4gIGFyci5yZWFkSW50QkUgPSBCUC5yZWFkSW50QkVcbiAgYXJyLnJlYWRJbnQ4ID0gQlAucmVhZEludDhcbiAgYXJyLnJlYWRJbnQxNkxFID0gQlAucmVhZEludDE2TEVcbiAgYXJyLnJlYWRJbnQxNkJFID0gQlAucmVhZEludDE2QkVcbiAgYXJyLnJlYWRJbnQzMkxFID0gQlAucmVhZEludDMyTEVcbiAgYXJyLnJlYWRJbnQzMkJFID0gQlAucmVhZEludDMyQkVcbiAgYXJyLnJlYWRGbG9hdExFID0gQlAucmVhZEZsb2F0TEVcbiAgYXJyLnJlYWRGbG9hdEJFID0gQlAucmVhZEZsb2F0QkVcbiAgYXJyLnJlYWREb3VibGVMRSA9IEJQLnJlYWREb3VibGVMRVxuICBhcnIucmVhZERvdWJsZUJFID0gQlAucmVhZERvdWJsZUJFXG4gIGFyci53cml0ZVVJbnQ4ID0gQlAud3JpdGVVSW50OFxuICBhcnIud3JpdGVVSW50TEUgPSBCUC53cml0ZVVJbnRMRVxuICBhcnIud3JpdGVVSW50QkUgPSBCUC53cml0ZVVJbnRCRVxuICBhcnIud3JpdGVVSW50MTZMRSA9IEJQLndyaXRlVUludDE2TEVcbiAgYXJyLndyaXRlVUludDE2QkUgPSBCUC53cml0ZVVJbnQxNkJFXG4gIGFyci53cml0ZVVJbnQzMkxFID0gQlAud3JpdGVVSW50MzJMRVxuICBhcnIud3JpdGVVSW50MzJCRSA9IEJQLndyaXRlVUludDMyQkVcbiAgYXJyLndyaXRlSW50TEUgPSBCUC53cml0ZUludExFXG4gIGFyci53cml0ZUludEJFID0gQlAud3JpdGVJbnRCRVxuICBhcnIud3JpdGVJbnQ4ID0gQlAud3JpdGVJbnQ4XG4gIGFyci53cml0ZUludDE2TEUgPSBCUC53cml0ZUludDE2TEVcbiAgYXJyLndyaXRlSW50MTZCRSA9IEJQLndyaXRlSW50MTZCRVxuICBhcnIud3JpdGVJbnQzMkxFID0gQlAud3JpdGVJbnQzMkxFXG4gIGFyci53cml0ZUludDMyQkUgPSBCUC53cml0ZUludDMyQkVcbiAgYXJyLndyaXRlRmxvYXRMRSA9IEJQLndyaXRlRmxvYXRMRVxuICBhcnIud3JpdGVGbG9hdEJFID0gQlAud3JpdGVGbG9hdEJFXG4gIGFyci53cml0ZURvdWJsZUxFID0gQlAud3JpdGVEb3VibGVMRVxuICBhcnIud3JpdGVEb3VibGVCRSA9IEJQLndyaXRlRG91YmxlQkVcbiAgYXJyLmZpbGwgPSBCUC5maWxsXG4gIGFyci5pbnNwZWN0ID0gQlAuaW5zcGVjdFxuICBhcnIudG9BcnJheUJ1ZmZlciA9IEJQLnRvQXJyYXlCdWZmZXJcblxuICByZXR1cm4gYXJyXG59XG5cbnZhciBJTlZBTElEX0JBU0U2NF9SRSA9IC9bXitcXC8wLTlBLVphLXotX10vZ1xuXG5mdW5jdGlvbiBiYXNlNjRjbGVhbiAoc3RyKSB7XG4gIC8vIE5vZGUgc3RyaXBzIG91dCBpbnZhbGlkIGNoYXJhY3RlcnMgbGlrZSBcXG4gYW5kIFxcdCBmcm9tIHRoZSBzdHJpbmcsIGJhc2U2NC1qcyBkb2VzIG5vdFxuICBzdHIgPSBzdHJpbmd0cmltKHN0cikucmVwbGFjZShJTlZBTElEX0JBU0U2NF9SRSwgJycpXG4gIC8vIE5vZGUgY29udmVydHMgc3RyaW5ncyB3aXRoIGxlbmd0aCA8IDIgdG8gJydcbiAgaWYgKHN0ci5sZW5ndGggPCAyKSByZXR1cm4gJydcbiAgLy8gTm9kZSBhbGxvd3MgZm9yIG5vbi1wYWRkZWQgYmFzZTY0IHN0cmluZ3MgKG1pc3NpbmcgdHJhaWxpbmcgPT09KSwgYmFzZTY0LWpzIGRvZXMgbm90XG4gIHdoaWxlIChzdHIubGVuZ3RoICUgNCAhPT0gMCkge1xuICAgIHN0ciA9IHN0ciArICc9J1xuICB9XG4gIHJldHVybiBzdHJcbn1cblxuZnVuY3Rpb24gc3RyaW5ndHJpbSAoc3RyKSB7XG4gIGlmIChzdHIudHJpbSkgcmV0dXJuIHN0ci50cmltKClcbiAgcmV0dXJuIHN0ci5yZXBsYWNlKC9eXFxzK3xcXHMrJC9nLCAnJylcbn1cblxuZnVuY3Rpb24gdG9IZXggKG4pIHtcbiAgaWYgKG4gPCAxNikgcmV0dXJuICcwJyArIG4udG9TdHJpbmcoMTYpXG4gIHJldHVybiBuLnRvU3RyaW5nKDE2KVxufVxuXG5mdW5jdGlvbiB1dGY4VG9CeXRlcyAoc3RyaW5nLCB1bml0cykge1xuICB1bml0cyA9IHVuaXRzIHx8IEluZmluaXR5XG4gIHZhciBjb2RlUG9pbnRcbiAgdmFyIGxlbmd0aCA9IHN0cmluZy5sZW5ndGhcbiAgdmFyIGxlYWRTdXJyb2dhdGUgPSBudWxsXG4gIHZhciBieXRlcyA9IFtdXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIGNvZGVQb2ludCA9IHN0cmluZy5jaGFyQ29kZUF0KGkpXG5cbiAgICAvLyBpcyBzdXJyb2dhdGUgY29tcG9uZW50XG4gICAgaWYgKGNvZGVQb2ludCA+IDB4RDdGRiAmJiBjb2RlUG9pbnQgPCAweEUwMDApIHtcbiAgICAgIC8vIGxhc3QgY2hhciB3YXMgYSBsZWFkXG4gICAgICBpZiAoIWxlYWRTdXJyb2dhdGUpIHtcbiAgICAgICAgLy8gbm8gbGVhZCB5ZXRcbiAgICAgICAgaWYgKGNvZGVQb2ludCA+IDB4REJGRikge1xuICAgICAgICAgIC8vIHVuZXhwZWN0ZWQgdHJhaWxcbiAgICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9IGVsc2UgaWYgKGkgKyAxID09PSBsZW5ndGgpIHtcbiAgICAgICAgICAvLyB1bnBhaXJlZCBsZWFkXG4gICAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHZhbGlkIGxlYWRcbiAgICAgICAgbGVhZFN1cnJvZ2F0ZSA9IGNvZGVQb2ludFxuXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIC8vIDIgbGVhZHMgaW4gYSByb3dcbiAgICAgIGlmIChjb2RlUG9pbnQgPCAweERDMDApIHtcbiAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgIGxlYWRTdXJyb2dhdGUgPSBjb2RlUG9pbnRcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gdmFsaWQgc3Vycm9nYXRlIHBhaXJcbiAgICAgIGNvZGVQb2ludCA9IChsZWFkU3Vycm9nYXRlIC0gMHhEODAwIDw8IDEwIHwgY29kZVBvaW50IC0gMHhEQzAwKSArIDB4MTAwMDBcbiAgICB9IGVsc2UgaWYgKGxlYWRTdXJyb2dhdGUpIHtcbiAgICAgIC8vIHZhbGlkIGJtcCBjaGFyLCBidXQgbGFzdCBjaGFyIHdhcyBhIGxlYWRcbiAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgIH1cblxuICAgIGxlYWRTdXJyb2dhdGUgPSBudWxsXG5cbiAgICAvLyBlbmNvZGUgdXRmOFxuICAgIGlmIChjb2RlUG9pbnQgPCAweDgwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDEpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goY29kZVBvaW50KVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHg4MDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMikgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiB8IDB4QzAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDEwMDAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDMpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweEMgfCAweEUwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2ICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDExMDAwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSA0KSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHgxMiB8IDB4RjAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweEMgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY29kZSBwb2ludCcpXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGJ5dGVzXG59XG5cbmZ1bmN0aW9uIGFzY2lpVG9CeXRlcyAoc3RyKSB7XG4gIHZhciBieXRlQXJyYXkgPSBbXVxuICBmb3IgKHZhciBpID0gMDsgaSA8IHN0ci5sZW5ndGg7IGkrKykge1xuICAgIC8vIE5vZGUncyBjb2RlIHNlZW1zIHRvIGJlIGRvaW5nIHRoaXMgYW5kIG5vdCAmIDB4N0YuLlxuICAgIGJ5dGVBcnJheS5wdXNoKHN0ci5jaGFyQ29kZUF0KGkpICYgMHhGRilcbiAgfVxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIHV0ZjE2bGVUb0J5dGVzIChzdHIsIHVuaXRzKSB7XG4gIHZhciBjLCBoaSwgbG9cbiAgdmFyIGJ5dGVBcnJheSA9IFtdXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKCh1bml0cyAtPSAyKSA8IDApIGJyZWFrXG5cbiAgICBjID0gc3RyLmNoYXJDb2RlQXQoaSlcbiAgICBoaSA9IGMgPj4gOFxuICAgIGxvID0gYyAlIDI1NlxuICAgIGJ5dGVBcnJheS5wdXNoKGxvKVxuICAgIGJ5dGVBcnJheS5wdXNoKGhpKVxuICB9XG5cbiAgcmV0dXJuIGJ5dGVBcnJheVxufVxuXG5mdW5jdGlvbiBiYXNlNjRUb0J5dGVzIChzdHIpIHtcbiAgcmV0dXJuIGJhc2U2NC50b0J5dGVBcnJheShiYXNlNjRjbGVhbihzdHIpKVxufVxuXG5mdW5jdGlvbiBibGl0QnVmZmVyIChzcmMsIGRzdCwgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIGlmICgoaSArIG9mZnNldCA+PSBkc3QubGVuZ3RoKSB8fCAoaSA+PSBzcmMubGVuZ3RoKSkgYnJlYWtcbiAgICBkc3RbaSArIG9mZnNldF0gPSBzcmNbaV1cbiAgfVxuICByZXR1cm4gaVxufVxuIiwidmFyIGxvb2t1cCA9ICdBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvJztcblxuOyhmdW5jdGlvbiAoZXhwb3J0cykge1xuXHQndXNlIHN0cmljdCc7XG5cbiAgdmFyIEFyciA9ICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpXG4gICAgPyBVaW50OEFycmF5XG4gICAgOiBBcnJheVxuXG5cdHZhciBQTFVTICAgPSAnKycuY2hhckNvZGVBdCgwKVxuXHR2YXIgU0xBU0ggID0gJy8nLmNoYXJDb2RlQXQoMClcblx0dmFyIE5VTUJFUiA9ICcwJy5jaGFyQ29kZUF0KDApXG5cdHZhciBMT1dFUiAgPSAnYScuY2hhckNvZGVBdCgwKVxuXHR2YXIgVVBQRVIgID0gJ0EnLmNoYXJDb2RlQXQoMClcblx0dmFyIFBMVVNfVVJMX1NBRkUgPSAnLScuY2hhckNvZGVBdCgwKVxuXHR2YXIgU0xBU0hfVVJMX1NBRkUgPSAnXycuY2hhckNvZGVBdCgwKVxuXG5cdGZ1bmN0aW9uIGRlY29kZSAoZWx0KSB7XG5cdFx0dmFyIGNvZGUgPSBlbHQuY2hhckNvZGVBdCgwKVxuXHRcdGlmIChjb2RlID09PSBQTFVTIHx8XG5cdFx0ICAgIGNvZGUgPT09IFBMVVNfVVJMX1NBRkUpXG5cdFx0XHRyZXR1cm4gNjIgLy8gJysnXG5cdFx0aWYgKGNvZGUgPT09IFNMQVNIIHx8XG5cdFx0ICAgIGNvZGUgPT09IFNMQVNIX1VSTF9TQUZFKVxuXHRcdFx0cmV0dXJuIDYzIC8vICcvJ1xuXHRcdGlmIChjb2RlIDwgTlVNQkVSKVxuXHRcdFx0cmV0dXJuIC0xIC8vbm8gbWF0Y2hcblx0XHRpZiAoY29kZSA8IE5VTUJFUiArIDEwKVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBOVU1CRVIgKyAyNiArIDI2XG5cdFx0aWYgKGNvZGUgPCBVUFBFUiArIDI2KVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBVUFBFUlxuXHRcdGlmIChjb2RlIDwgTE9XRVIgKyAyNilcblx0XHRcdHJldHVybiBjb2RlIC0gTE9XRVIgKyAyNlxuXHR9XG5cblx0ZnVuY3Rpb24gYjY0VG9CeXRlQXJyYXkgKGI2NCkge1xuXHRcdHZhciBpLCBqLCBsLCB0bXAsIHBsYWNlSG9sZGVycywgYXJyXG5cblx0XHRpZiAoYjY0Lmxlbmd0aCAlIDQgPiAwKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgc3RyaW5nLiBMZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIDQnKVxuXHRcdH1cblxuXHRcdC8vIHRoZSBudW1iZXIgb2YgZXF1YWwgc2lnbnMgKHBsYWNlIGhvbGRlcnMpXG5cdFx0Ly8gaWYgdGhlcmUgYXJlIHR3byBwbGFjZWhvbGRlcnMsIHRoYW4gdGhlIHR3byBjaGFyYWN0ZXJzIGJlZm9yZSBpdFxuXHRcdC8vIHJlcHJlc2VudCBvbmUgYnl0ZVxuXHRcdC8vIGlmIHRoZXJlIGlzIG9ubHkgb25lLCB0aGVuIHRoZSB0aHJlZSBjaGFyYWN0ZXJzIGJlZm9yZSBpdCByZXByZXNlbnQgMiBieXRlc1xuXHRcdC8vIHRoaXMgaXMganVzdCBhIGNoZWFwIGhhY2sgdG8gbm90IGRvIGluZGV4T2YgdHdpY2Vcblx0XHR2YXIgbGVuID0gYjY0Lmxlbmd0aFxuXHRcdHBsYWNlSG9sZGVycyA9ICc9JyA9PT0gYjY0LmNoYXJBdChsZW4gLSAyKSA/IDIgOiAnPScgPT09IGI2NC5jaGFyQXQobGVuIC0gMSkgPyAxIDogMFxuXG5cdFx0Ly8gYmFzZTY0IGlzIDQvMyArIHVwIHRvIHR3byBjaGFyYWN0ZXJzIG9mIHRoZSBvcmlnaW5hbCBkYXRhXG5cdFx0YXJyID0gbmV3IEFycihiNjQubGVuZ3RoICogMyAvIDQgLSBwbGFjZUhvbGRlcnMpXG5cblx0XHQvLyBpZiB0aGVyZSBhcmUgcGxhY2Vob2xkZXJzLCBvbmx5IGdldCB1cCB0byB0aGUgbGFzdCBjb21wbGV0ZSA0IGNoYXJzXG5cdFx0bCA9IHBsYWNlSG9sZGVycyA+IDAgPyBiNjQubGVuZ3RoIC0gNCA6IGI2NC5sZW5ndGhcblxuXHRcdHZhciBMID0gMFxuXG5cdFx0ZnVuY3Rpb24gcHVzaCAodikge1xuXHRcdFx0YXJyW0wrK10gPSB2XG5cdFx0fVxuXG5cdFx0Zm9yIChpID0gMCwgaiA9IDA7IGkgPCBsOyBpICs9IDQsIGogKz0gMykge1xuXHRcdFx0dG1wID0gKGRlY29kZShiNjQuY2hhckF0KGkpKSA8PCAxOCkgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA8PCAxMikgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDIpKSA8PCA2KSB8IGRlY29kZShiNjQuY2hhckF0KGkgKyAzKSlcblx0XHRcdHB1c2goKHRtcCAmIDB4RkYwMDAwKSA+PiAxNilcblx0XHRcdHB1c2goKHRtcCAmIDB4RkYwMCkgPj4gOClcblx0XHRcdHB1c2godG1wICYgMHhGRilcblx0XHR9XG5cblx0XHRpZiAocGxhY2VIb2xkZXJzID09PSAyKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDIpIHwgKGRlY29kZShiNjQuY2hhckF0KGkgKyAxKSkgPj4gNClcblx0XHRcdHB1c2godG1wICYgMHhGRilcblx0XHR9IGVsc2UgaWYgKHBsYWNlSG9sZGVycyA9PT0gMSkge1xuXHRcdFx0dG1wID0gKGRlY29kZShiNjQuY2hhckF0KGkpKSA8PCAxMCkgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA8PCA0KSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMikpID4+IDIpXG5cdFx0XHRwdXNoKCh0bXAgPj4gOCkgJiAweEZGKVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH1cblxuXHRcdHJldHVybiBhcnJcblx0fVxuXG5cdGZ1bmN0aW9uIHVpbnQ4VG9CYXNlNjQgKHVpbnQ4KSB7XG5cdFx0dmFyIGksXG5cdFx0XHRleHRyYUJ5dGVzID0gdWludDgubGVuZ3RoICUgMywgLy8gaWYgd2UgaGF2ZSAxIGJ5dGUgbGVmdCwgcGFkIDIgYnl0ZXNcblx0XHRcdG91dHB1dCA9IFwiXCIsXG5cdFx0XHR0ZW1wLCBsZW5ndGhcblxuXHRcdGZ1bmN0aW9uIGVuY29kZSAobnVtKSB7XG5cdFx0XHRyZXR1cm4gbG9va3VwLmNoYXJBdChudW0pXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gdHJpcGxldFRvQmFzZTY0IChudW0pIHtcblx0XHRcdHJldHVybiBlbmNvZGUobnVtID4+IDE4ICYgMHgzRikgKyBlbmNvZGUobnVtID4+IDEyICYgMHgzRikgKyBlbmNvZGUobnVtID4+IDYgJiAweDNGKSArIGVuY29kZShudW0gJiAweDNGKVxuXHRcdH1cblxuXHRcdC8vIGdvIHRocm91Z2ggdGhlIGFycmF5IGV2ZXJ5IHRocmVlIGJ5dGVzLCB3ZSdsbCBkZWFsIHdpdGggdHJhaWxpbmcgc3R1ZmYgbGF0ZXJcblx0XHRmb3IgKGkgPSAwLCBsZW5ndGggPSB1aW50OC5sZW5ndGggLSBleHRyYUJ5dGVzOyBpIDwgbGVuZ3RoOyBpICs9IDMpIHtcblx0XHRcdHRlbXAgPSAodWludDhbaV0gPDwgMTYpICsgKHVpbnQ4W2kgKyAxXSA8PCA4KSArICh1aW50OFtpICsgMl0pXG5cdFx0XHRvdXRwdXQgKz0gdHJpcGxldFRvQmFzZTY0KHRlbXApXG5cdFx0fVxuXG5cdFx0Ly8gcGFkIHRoZSBlbmQgd2l0aCB6ZXJvcywgYnV0IG1ha2Ugc3VyZSB0byBub3QgZm9yZ2V0IHRoZSBleHRyYSBieXRlc1xuXHRcdHN3aXRjaCAoZXh0cmFCeXRlcykge1xuXHRcdFx0Y2FzZSAxOlxuXHRcdFx0XHR0ZW1wID0gdWludDhbdWludDgubGVuZ3RoIC0gMV1cblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSh0ZW1wID4+IDIpXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPDwgNCkgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gJz09J1xuXHRcdFx0XHRicmVha1xuXHRcdFx0Y2FzZSAyOlxuXHRcdFx0XHR0ZW1wID0gKHVpbnQ4W3VpbnQ4Lmxlbmd0aCAtIDJdIDw8IDgpICsgKHVpbnQ4W3VpbnQ4Lmxlbmd0aCAtIDFdKVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKHRlbXAgPj4gMTApXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPj4gNCkgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKCh0ZW1wIDw8IDIpICYgMHgzRilcblx0XHRcdFx0b3V0cHV0ICs9ICc9J1xuXHRcdFx0XHRicmVha1xuXHRcdH1cblxuXHRcdHJldHVybiBvdXRwdXRcblx0fVxuXG5cdGV4cG9ydHMudG9CeXRlQXJyYXkgPSBiNjRUb0J5dGVBcnJheVxuXHRleHBvcnRzLmZyb21CeXRlQXJyYXkgPSB1aW50OFRvQmFzZTY0XG59KHR5cGVvZiBleHBvcnRzID09PSAndW5kZWZpbmVkJyA/ICh0aGlzLmJhc2U2NGpzID0ge30pIDogZXhwb3J0cykpXG4iLCJleHBvcnRzLnJlYWQgPSBmdW5jdGlvbiAoYnVmZmVyLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbVxuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIG5CaXRzID0gLTdcbiAgdmFyIGkgPSBpc0xFID8gKG5CeXRlcyAtIDEpIDogMFxuICB2YXIgZCA9IGlzTEUgPyAtMSA6IDFcbiAgdmFyIHMgPSBidWZmZXJbb2Zmc2V0ICsgaV1cblxuICBpICs9IGRcblxuICBlID0gcyAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBzID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBlTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IGUgPSBlICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgbSA9IGUgJiAoKDEgPDwgKC1uQml0cykpIC0gMSlcbiAgZSA+Pj0gKC1uQml0cylcbiAgbkJpdHMgKz0gbUxlblxuICBmb3IgKDsgbkJpdHMgPiAwOyBtID0gbSAqIDI1NiArIGJ1ZmZlcltvZmZzZXQgKyBpXSwgaSArPSBkLCBuQml0cyAtPSA4KSB7fVxuXG4gIGlmIChlID09PSAwKSB7XG4gICAgZSA9IDEgLSBlQmlhc1xuICB9IGVsc2UgaWYgKGUgPT09IGVNYXgpIHtcbiAgICByZXR1cm4gbSA/IE5hTiA6ICgocyA/IC0xIDogMSkgKiBJbmZpbml0eSlcbiAgfSBlbHNlIHtcbiAgICBtID0gbSArIE1hdGgucG93KDIsIG1MZW4pXG4gICAgZSA9IGUgLSBlQmlhc1xuICB9XG4gIHJldHVybiAocyA/IC0xIDogMSkgKiBtICogTWF0aC5wb3coMiwgZSAtIG1MZW4pXG59XG5cbmV4cG9ydHMud3JpdGUgPSBmdW5jdGlvbiAoYnVmZmVyLCB2YWx1ZSwgb2Zmc2V0LCBpc0xFLCBtTGVuLCBuQnl0ZXMpIHtcbiAgdmFyIGUsIG0sIGNcbiAgdmFyIGVMZW4gPSBuQnl0ZXMgKiA4IC0gbUxlbiAtIDFcbiAgdmFyIGVNYXggPSAoMSA8PCBlTGVuKSAtIDFcbiAgdmFyIGVCaWFzID0gZU1heCA+PiAxXG4gIHZhciBydCA9IChtTGVuID09PSAyMyA/IE1hdGgucG93KDIsIC0yNCkgLSBNYXRoLnBvdygyLCAtNzcpIDogMClcbiAgdmFyIGkgPSBpc0xFID8gMCA6IChuQnl0ZXMgLSAxKVxuICB2YXIgZCA9IGlzTEUgPyAxIDogLTFcbiAgdmFyIHMgPSB2YWx1ZSA8IDAgfHwgKHZhbHVlID09PSAwICYmIDEgLyB2YWx1ZSA8IDApID8gMSA6IDBcblxuICB2YWx1ZSA9IE1hdGguYWJzKHZhbHVlKVxuXG4gIGlmIChpc05hTih2YWx1ZSkgfHwgdmFsdWUgPT09IEluZmluaXR5KSB7XG4gICAgbSA9IGlzTmFOKHZhbHVlKSA/IDEgOiAwXG4gICAgZSA9IGVNYXhcbiAgfSBlbHNlIHtcbiAgICBlID0gTWF0aC5mbG9vcihNYXRoLmxvZyh2YWx1ZSkgLyBNYXRoLkxOMilcbiAgICBpZiAodmFsdWUgKiAoYyA9IE1hdGgucG93KDIsIC1lKSkgPCAxKSB7XG4gICAgICBlLS1cbiAgICAgIGMgKj0gMlxuICAgIH1cbiAgICBpZiAoZSArIGVCaWFzID49IDEpIHtcbiAgICAgIHZhbHVlICs9IHJ0IC8gY1xuICAgIH0gZWxzZSB7XG4gICAgICB2YWx1ZSArPSBydCAqIE1hdGgucG93KDIsIDEgLSBlQmlhcylcbiAgICB9XG4gICAgaWYgKHZhbHVlICogYyA+PSAyKSB7XG4gICAgICBlKytcbiAgICAgIGMgLz0gMlxuICAgIH1cblxuICAgIGlmIChlICsgZUJpYXMgPj0gZU1heCkge1xuICAgICAgbSA9IDBcbiAgICAgIGUgPSBlTWF4XG4gICAgfSBlbHNlIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgbSA9ICh2YWx1ZSAqIGMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gZSArIGVCaWFzXG4gICAgfSBlbHNlIHtcbiAgICAgIG0gPSB2YWx1ZSAqIE1hdGgucG93KDIsIGVCaWFzIC0gMSkgKiBNYXRoLnBvdygyLCBtTGVuKVxuICAgICAgZSA9IDBcbiAgICB9XG4gIH1cblxuICBmb3IgKDsgbUxlbiA+PSA4OyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBtICYgMHhmZiwgaSArPSBkLCBtIC89IDI1NiwgbUxlbiAtPSA4KSB7fVxuXG4gIGUgPSAoZSA8PCBtTGVuKSB8IG1cbiAgZUxlbiArPSBtTGVuXG4gIGZvciAoOyBlTGVuID4gMDsgYnVmZmVyW29mZnNldCArIGldID0gZSAmIDB4ZmYsIGkgKz0gZCwgZSAvPSAyNTYsIGVMZW4gLT0gOCkge31cblxuICBidWZmZXJbb2Zmc2V0ICsgaSAtIGRdIHw9IHMgKiAxMjhcbn1cbiIsIlxuLyoqXG4gKiBpc0FycmF5XG4gKi9cblxudmFyIGlzQXJyYXkgPSBBcnJheS5pc0FycmF5O1xuXG4vKipcbiAqIHRvU3RyaW5nXG4gKi9cblxudmFyIHN0ciA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmc7XG5cbi8qKlxuICogV2hldGhlciBvciBub3QgdGhlIGdpdmVuIGB2YWxgXG4gKiBpcyBhbiBhcnJheS5cbiAqXG4gKiBleGFtcGxlOlxuICpcbiAqICAgICAgICBpc0FycmF5KFtdKTtcbiAqICAgICAgICAvLyA+IHRydWVcbiAqICAgICAgICBpc0FycmF5KGFyZ3VtZW50cyk7XG4gKiAgICAgICAgLy8gPiBmYWxzZVxuICogICAgICAgIGlzQXJyYXkoJycpO1xuICogICAgICAgIC8vID4gZmFsc2VcbiAqXG4gKiBAcGFyYW0ge21peGVkfSB2YWxcbiAqIEByZXR1cm4ge2Jvb2x9XG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBpc0FycmF5IHx8IGZ1bmN0aW9uICh2YWwpIHtcbiAgcmV0dXJuICEhIHZhbCAmJiAnW29iamVjdCBBcnJheV0nID09IHN0ci5jYWxsKHZhbCk7XG59O1xuIiwibW9kdWxlLmV4cG9ydHM9e1xuICAgIFwidmVyc2lvblwiOiBcIlwiXG59XG4iLCIvKipcbiAqIEVwaWNlbnRlciBKYXZhc2NyaXB0IGxpYnJhcmllc1xuICogdjwlPSB2ZXJzaW9uICU+XG4gKiBodHRwczovL2dpdGh1Yi5jb20vZm9yaW8vZXBpY2VudGVyLWpzLWxpYnNcbiAqL1xuXG52YXIgRiA9IHtcbiAgICB1dGlsOiB7fSxcbiAgICBmYWN0b3J5OiB7fSxcbiAgICB0cmFuc3BvcnQ6IHt9LFxuICAgIHN0b3JlOiB7fSxcbiAgICBzZXJ2aWNlOiB7fSxcbiAgICBtYW5hZ2VyOiB7XG4gICAgICAgIHN0cmF0ZWd5OiB7fVxuICAgIH0sXG5cbn07XG5cbkYudXRpbC5xdWVyeSA9IHJlcXVpcmUoJy4vdXRpbC9xdWVyeS11dGlsJyk7XG5GLnV0aWwubWFrZVNlcXVlbmNlID0gcmVxdWlyZSgnLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbkYudXRpbC5ydW4gPSByZXF1aXJlKCcuL3V0aWwvcnVuLXV0aWwnKTtcbkYudXRpbC5jbGFzc0Zyb20gPSByZXF1aXJlKCcuL3V0aWwvaW5oZXJpdCcpO1xuXG5GLmZhY3RvcnkuVHJhbnNwb3J0ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuRi50cmFuc3BvcnQuQWpheCA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0L2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcblxuRi5zZXJ2aWNlLlVSTCA9IHJlcXVpcmUoJy4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbkYuc2VydmljZS5Db25maWcgPSByZXF1aXJlKCcuL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuUnVuID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkZpbGUgPSByZXF1aXJlKCcuL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuVmFyaWFibGVzID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkRhdGEgPSByZXF1aXJlKCcuL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkF1dGggPSByZXF1aXJlKCcuL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLldvcmxkID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuU3RhdGUgPSByZXF1aXJlKCcuL3NlcnZpY2Uvc3RhdGUtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Vc2VyID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VzZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5NZW1iZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvbWVtYmVyLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuQXNzZXQgPSByZXF1aXJlKCcuL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXInKTtcblxuRi5zdG9yZS5Db29raWUgPSByZXF1aXJlKCcuL3N0b3JlL2Nvb2tpZS1zdG9yZScpO1xuRi5mYWN0b3J5LlN0b3JlID0gcmVxdWlyZSgnLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG5cbkYubWFuYWdlci5TY2VuYXJpb01hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3NjZW5hcmlvLW1hbmFnZXInKTtcbkYubWFuYWdlci5SdW5NYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9hdXRoLW1hbmFnZXInKTtcbkYubWFuYWdlci5Xb3JsZE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3dvcmxkLW1hbmFnZXInKTtcblxuRi5tYW5hZ2VyLnN0cmF0ZWd5WydhbHdheXMtbmV3J10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2Fsd2F5cy1uZXctc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnY29uZGl0aW9uYWwtY3JlYXRpb24nXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneS5pZGVudGl0eSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvaWRlbnRpdHktc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLW1pc3NpbmcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLW1pc3Npbmctc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLW1pc3NpbmcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLW1pc3Npbmctc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLXBlcnNpc3RlZCddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5Jyk7XG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ25ldy1pZi1pbml0aWFsaXplZCddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtaW5pdGlhbGl6ZWQtc3RyYXRlZ3knKTtcblxuRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyJyk7XG5GLnNlcnZpY2UuQ2hhbm5lbCA9IHJlcXVpcmUoJy4vc2VydmljZS9jaGFubmVsLXNlcnZpY2UnKTtcblxuRi52ZXJzaW9uID0gJzwlPSB2ZXJzaW9uICU+JztcbkYuYXBpID0gcmVxdWlyZSgnLi9hcGktdmVyc2lvbi5qc29uJyk7XG5cbmdsb2JhbC5GID0gRjtcbm1vZHVsZS5leHBvcnRzID0gRjtcbiIsIi8qKlxuKiAjIyBBdXRob3JpemF0aW9uIE1hbmFnZXJcbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byBtYW5hZ2UgdXNlciBhdXRoZW50aWNhdGlvbiAobG9nZ2luZyBpbiBhbmQgb3V0KSBhbmQgYXV0aG9yaXphdGlvbiAoa2VlcGluZyB0cmFjayBvZiB0b2tlbnMsIHNlc3Npb25zLCBhbmQgZ3JvdXBzKSBmb3IgcHJvamVjdHMuXG4qXG4qIFRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgaXMgbW9zdCB1c2VmdWwgZm9yIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSkgd2l0aCBhbiBhY2Nlc3MgbGV2ZWwgb2YgW0F1dGhlbnRpY2F0ZWRdKC4uLy4uLy4uL2dsb3NzYXJ5LyNhY2Nlc3MpLiBUaGVzZSBwcm9qZWN0cyBhcmUgYWNjZXNzZWQgYnkgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSB3aG8gYXJlIG1lbWJlcnMgb2Ygb25lIG9yIG1vcmUgW2dyb3Vwc10oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykuXG4qXG4qICMjIyNVc2luZyB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyXG4qXG4qIFRvIHVzZSB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdC4gVGhlbiwgbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQ6XG4qXG4qICAgICAgIHZhciBhdXRoTWdyID0gbmV3IEYubWFuYWdlci5BdXRoTWFuYWdlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB1c2VyTmFtZTogJ2VuZHVzZXIxJyxcbiogICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnXG4qICAgICAgIH0pO1xuKiAgICAgICBhdXRoTWdyLmxvZ2luKCkudGhlbihmdW5jdGlvbiAoKSB7XG4qICAgICAgICAgICBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiogICAgICAgfSk7XG4qXG4qXG4qIFRoZSBgb3B0aW9uc2Agb2JqZWN0IHBhc3NlZCB0byB0aGUgYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCBjYWxsIGNhbiBpbmNsdWRlOlxuKlxuKiAgICogYGFjY291bnRgOiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiogICAqIGB1c2VyTmFtZWA6IEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi5cbiogICAqIGBwYXNzd29yZGA6IFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGUgcHJvamVjdCB0byBsb2cgdGhpcyB1c2VyIGludG8uIE9wdGlvbmFsLlxuKiAgICogYGdyb3VwSWRgOiBJZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgZW5kIHVzZXJzIGlmIHRoZSBgcHJvamVjdGAgaXMgc3BlY2lmaWVkLlxuKlxuKiBJZiB5b3UgcHJlZmVyIHN0YXJ0aW5nIGZyb20gYSB0ZW1wbGF0ZSwgdGhlIEVwaWNlbnRlciBKUyBMaWJzIFtMb2dpbiBDb21wb25lbnRdKC4uLy4uLyNjb21wb25lbnRzKSB1c2VzIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgYXMgd2VsbC4gVGhpcyBzYW1wbGUgSFRNTCBwYWdlIChhbmQgYXNzb2NpYXRlZCBDU1MgYW5kIEpTIGZpbGVzKSBwcm92aWRlcyBhIGxvZ2luIGZvcm0gZm9yIHRlYW0gbWVtYmVycyBhbmQgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdC4gSXQgYWxzbyBpbmNsdWRlcyBhIGdyb3VwIHNlbGVjdG9yIGZvciBlbmQgdXNlcnMgdGhhdCBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBncm91cHMuXG4qL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgQXV0aEFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2F1dGgtYXBpLXNlcnZpY2UnKTtcbnZhciBNZW1iZXJBZGFwdGVyID0gcmVxdWlyZSgnLi4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBCdWZmZXIgPSByZXF1aXJlKCdidWZmZXInKS5CdWZmZXI7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogV2hlcmUgdG8gc3RvcmUgdXNlciBhY2Nlc3MgdG9rZW5zIGZvciB0ZW1wb3JhcnkgYWNjZXNzLiBEZWZhdWx0cyB0byBzdG9yaW5nIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLlxuICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICovXG4gICAgc3RvcmU6IHsgc3luY2hyb25vdXM6IHRydWUgfVxufTtcblxudmFyIEVQSV9DT09LSUVfS0VZID0ga2V5TmFtZXMuRVBJX0NPT0tJRV9LRVk7XG52YXIgRVBJX1NFU1NJT05fS0VZID0ga2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZO1xudmFyIHN0b3JlO1xudmFyIHRva2VuO1xudmFyIHNlc3Npb247XG5cbmZ1bmN0aW9uIHNhdmVTZXNzaW9uKHVzZXJJbmZvLCBzdG9yZSkge1xuICAgIHZhciBzZXJpYWxpemVkID0gSlNPTi5zdHJpbmdpZnkodXNlckluZm8pO1xuICAgIHN0b3JlLnNldChFUElfU0VTU0lPTl9LRVksIHNlcmlhbGl6ZWQpO1xuXG4gICAgLy9qc2hpbnQgY2FtZWxjYXNlOiBmYWxzZVxuICAgIC8vanNjczpkaXNhYmxlXG4gICAgc3RvcmUuc2V0KEVQSV9DT09LSUVfS0VZLCB1c2VySW5mby5hdXRoX3Rva2VuKTtcbn1cblxuZnVuY3Rpb24gZ2V0U2Vzc2lvbihzdG9yZSkge1xuICAgIHZhciBzZXNzaW9uID0gc3RvcmUuZ2V0KEVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9JztcbiAgICByZXR1cm4gSlNPTi5wYXJzZShzZXNzaW9uKTtcbn1cblxuZnVuY3Rpb24gQXV0aE1hbmFnZXIob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2UodGhpcy5vcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIHRoaXMuaXNMb2NhbCA9IHVybENvbmZpZy5pc0xvY2FsaG9zdCgpO1xuXG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB0aGlzLm9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICAvLyBudWxsIG1pZ2h0IHNwZWNpZmllZCB0byBkaXNhYmxlIHByb2plY3QgZmlsdGVyaW5nXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wcm9qZWN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdGhpcy5zdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh0aGlzLm9wdGlvbnMuc3RvcmUpO1xuICAgIHNlc3Npb24gPSBnZXRTZXNzaW9uKHRoaXMuc3RvcmUpO1xuICAgIHRva2VuID0gdGhpcy5zdG9yZS5nZXQoRVBJX0NPT0tJRV9LRVkpIHx8ICcnO1xuICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAvL2pzY3M6ZGlzYWJsZVxuICAgIHRoaXMuYXV0aEFkYXB0ZXIgPSBuZXcgQXV0aEFkYXB0ZXIodGhpcy5vcHRpb25zLCB7IHRva2VuOiBzZXNzaW9uLmF1dGhfdG9rZW4gfSk7XG59XG5cbnZhciBfZmluZFVzZXJJbkdyb3VwID0gZnVuY3Rpb24gKG1lbWJlcnMsIGlkKSB7XG4gICAgZm9yICh2YXIgaiA9IDA7IGo8bWVtYmVycy5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAobWVtYmVyc1tqXS51c2VySWQgPT09IGlkKSB7XG4gICAgICAgICAgICByZXR1cm4gbWVtYmVyc1tqXTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgcmV0dXJuIG51bGw7XG59O1xuXG5BdXRoTWFuYWdlci5wcm90b3R5cGUgPSAkLmV4dGVuZChBdXRoTWFuYWdlci5wcm90b3R5cGUsIHtcblxuICAgIC8qKlxuICAgICogTG9ncyB1c2VyIGluLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dpbih7XG4gICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgKiAgICAgICAgICAgdXNlck5hbWU6ICdlbmR1c2VyMScsXG4gICAgKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiAgICAqICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gZXhhY3RseSBvbmUgZ3JvdXBcbiAgICAqICAgICAgICAgICAgICAgLy8gKG9yIGlmIHRoZSBsb2dpbigpIGNhbGwgaXMgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGUgZ3JvdXAgaWQpXG4gICAgKiAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIGhlcmVcbiAgICAqICAgICAgICAgICB9KVxuICAgICogICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIG11bHRpcGxlIGdyb3VwcyxcbiAgICAqICAgICAgICAgICAgICAgLy8gdGhlIGxvZ2luKCkgY2FsbCBmYWlsc1xuICAgICogICAgICAgICAgICAgICAvLyBhbmQgcmV0dXJucyBhbGwgZ3JvdXBzIG9mIHdoaWNoIHRoZSB1c2VyIGlzIGEgbWVtYmVyXG4gICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IHN0YXR1c09iai51c2VyR3JvdXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5uYW1lLCBzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5ncm91cElkKTtcbiAgICAqICAgICAgICAgICAgICAgfVxuICAgICogICAgICAgICAgIH0pO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLiBJZiBub3QgcGFzc2VkIGluIHdoZW4gY3JlYXRpbmcgYW4gaW5zdGFuY2Ugb2YgdGhlIG1hbmFnZXIgKGBGLm1hbmFnZXIuQXV0aE1hbmFnZXIoKWApLCB0aGVzZSBvcHRpb25zIHNob3VsZCBpbmNsdWRlOlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmFjY291bnRgIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnVzZXJOYW1lYCBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMucGFzc3dvcmRgIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5wcm9qZWN0YCAoT3B0aW9uYWwpIFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhlIHByb2plY3QgdG8gbG9nIHRoaXMgdXNlciBpbnRvLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpZiB0aGUgYHByb2plY3RgIGlzIHNwZWNpZmllZCBhbmQgaWYgdGhlIGVuZCB1c2VycyBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3RoZXJ3aXNlIG9wdGlvbmFsLlxuICAgICovXG4gICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AsIGVycm9yOiAkLm5vb3AgfSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuICAgICAgICB2YXIgb3V0RXJyb3IgPSBhZGFwdGVyT3B0aW9ucy5lcnJvcjtcbiAgICAgICAgdmFyIGdyb3VwSWQgPSBhZGFwdGVyT3B0aW9ucy5ncm91cElkO1xuXG4gICAgICAgIHZhciBhY2NvdW50TmFtZSA9IChvcHRpb25zICYmIG9wdGlvbnMuYWNjb3VudCkgPyBvcHRpb25zLmFjY291bnQgOiB0aGlzLm9wdGlvbnMuYWNjb3VudDtcbiAgICAgICAgdmFyIHByb2plY3ROYW1lID0gKG9wdGlvbnMgJiYgb3B0aW9ucy5wcm9qZWN0KSA/IG9wdGlvbnMucHJvamVjdCA6IHRoaXMub3B0aW9ucy5wcm9qZWN0O1xuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuc3RvcmUucm9vdCA9PT0gdW5kZWZpbmVkICYmIGFjY291bnROYW1lICYmIHByb2plY3ROYW1lKSB7XG4gICAgICAgICAgICB0aGlzLnN0b3JlLnNlcnZpY2VPcHRpb25zLnJvb3QgPSB0aGlzLmlzTG9jYWwgPyAnLycgOiAnL2FwcC8nICsgYWNjb3VudE5hbWUgKyAnLycgKyBwcm9qZWN0TmFtZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBkZWNvZGVUb2tlbiA9IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgICAgdmFyIGVuY29kZWQgPSB0b2tlbi5zcGxpdCgnLicpWzFdO1xuICAgICAgICAgICAgd2hpbGUgKGVuY29kZWQubGVuZ3RoICUgNCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIGVuY29kZWQgKz0gJz0nO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZGVjb2RlID0gd2luZG93LmF0b2IgPyB3aW5kb3cuYXRvYiA6IGZ1bmN0aW9uIChlbmNvZGVkKSB7IHJldHVybiBuZXcgQnVmZmVyKGVuY29kZWQsICdiYXNlNjQnKS50b1N0cmluZygnYXNjaWknKTsgfTtcblxuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGVjb2RlKGVuY29kZWQpKTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgaGFuZGxlR3JvdXBFcnJvciA9IGZ1bmN0aW9uIChtZXNzYWdlLCBzdGF0dXNDb2RlLCBkYXRhKSB7XG4gICAgICAgICAgICAvLyBsb2dvdXQgdGhlIHVzZXIgc2luY2UgaXQncyBpbiBhbiBpbnZhbGlkIHN0YXRlIHdpdGggbm8gZ3JvdXAgc2VsZWN0ZWRcbiAgICAgICAgICAgIF90aGlzLmxvZ291dCgpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBlcnJvciA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkYXRhLCB7IHN0YXR1c1RleHQ6IG1lc3NhZ2UsIHN0YXR1czogc3RhdHVzQ29kZSB9KTtcbiAgICAgICAgICAgICAgICAkZC5yZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZVN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAgICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgICAgICB0b2tlbiA9IHJlc3BvbnNlLmFjY2Vzc190b2tlbjtcbiAgICAgICAgICAgIHZhciB1c2VySW5mbyA9IGRlY29kZVRva2VuKHRva2VuKTtcbiAgICAgICAgICAgIHZhciB1c2VyR3JvdXBPcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIGFkYXB0ZXJPcHRpb25zLCB7IHN1Y2Nlc3M6ICQubm9vcCwgdG9rZW46IHRva2VuIH0pO1xuICAgICAgICAgICAgX3RoaXMuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogdXNlckluZm8udXNlcl9pZCwgdG9rZW46IHRva2VuIH0sIHVzZXJHcm91cE9wdHMpLmRvbmUoIGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGEgPSB7YXV0aDogcmVzcG9uc2UsIHVzZXI6IHVzZXJJbmZvLCB1c2VyR3JvdXBzOiBtZW1iZXJJbmZvLCBncm91cFNlbGVjdGlvbjoge30gfTtcblxuICAgICAgICAgICAgICAgIHZhciBzZXNzaW9uSW5mbyA9IHtcbiAgICAgICAgICAgICAgICAgICAgJ2F1dGhfdG9rZW4nOiB0b2tlbixcbiAgICAgICAgICAgICAgICAgICAgJ2FjY291bnQnOiBhZGFwdGVyT3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgICAgICAncHJvamVjdCc6IGFkYXB0ZXJPcHRpb25zLnByb2plY3QsXG4gICAgICAgICAgICAgICAgICAgICd1c2VySWQnOiB1c2VySW5mby51c2VyX2lkXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAvLyBUaGUgZ3JvdXAgaXMgbm90IHJlcXVpcmVkIGlmIHRoZSB1c2VyIGlzIG5vdCBsb2dnaW5nIGludG8gYSBwcm9qZWN0XG4gICAgICAgICAgICAgICAgaWYgKCFhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHNhdmVTZXNzaW9uKHNlc3Npb25JbmZvLCBfdGhpcy5zdG9yZSk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBncm91cCA9IG51bGw7XG4gICAgICAgICAgICAgICAgaWYgKG1lbWJlckluZm8ubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoZSB1c2VyIGhhcyBubyBncm91cHMgYXNzb2NpYXRlZCBpbiB0aGlzIGFjY291bnQnLCA0MDEsIGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZW1iZXJJbmZvLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTZWxlY3QgdGhlIG9ubHkgZ3JvdXBcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBtZW1iZXJJbmZvWzBdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobWVtYmVySW5mby5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChncm91cElkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmlsdGVyZWRHcm91cHMgPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKHJlc0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc0dyb3VwLmdyb3VwSWQgPT09IGdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gZmlsdGVyZWRHcm91cHMubGVuZ3RoID09PSAxID8gZmlsdGVyZWRHcm91cHNbMF0gOiBudWxsO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBncm91cFNlbGVjdGlvbiA9IGdyb3VwLmdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEuZ3JvdXBTZWxlY3Rpb25bYWRhcHRlck9wdGlvbnMucHJvamVjdF0gPSBncm91cFNlbGVjdGlvbjtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNlc3Npb25JbmZvV2l0aEdyb3VwID0gJC5leHRlbmQoe30sIHNlc3Npb25JbmZvLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAnZ3JvdXBJZCc6IGdyb3VwLmdyb3VwSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAnZ3JvdXBOYW1lJzogZ3JvdXAubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICdpc0ZhYyc6IF9maW5kVXNlckluR3JvdXAoZ3JvdXAubWVtYmVycywgdXNlckluZm8udXNlcl9pZCkucm9sZSA9PT0gJ2ZhY2lsaXRhdG9yJ1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgc2F2ZVNlc3Npb24oc2Vzc2lvbkluZm9XaXRoR3JvdXAsIF90aGlzLnN0b3JlKTtcbiAgICAgICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoaXMgdXNlciBpcyBhc3NvY2lhdGVkIHdpdGggbW9yZSB0aGFuIG9uZSBncm91cC4gUGxlYXNlIHNwZWNpZnkgYSBncm91cCBpZCB0byBsb2cgaW50byBhbmQgdHJ5IGFnYWluJywgNDAzLCBkYXRhKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGhhbmRsZVN1Y2Nlc3M7XG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vIFRyeSB0byBsb2dpbiBhcyBhIHN5c3RlbSB1c2VyXG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuYWNjb3VudCA9IG51bGw7XG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuZXJyb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdChyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIF90aGlzLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuYXV0aEFkYXB0ZXIubG9naW4oYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAqIExvZ3MgdXNlciBvdXQuXG4gICAgKlxuICAgICogKipFeGFtcGxlKipcbiAgICAqXG4gICAgKiAgICAgICBhdXRoTWdyLmxvZ291dCgpO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICovXG4gICAgbG9nb3V0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgYWRhcHRlck9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHRva2VuOiB0b2tlbiB9LCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciByZW1vdmVDb29raWVGbiA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgc3RvcmUucmVtb3ZlKEVQSV9DT09LSUVfS0VZLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICBzdG9yZS5yZW1vdmUoRVBJX1NFU1NJT05fS0VZLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICB0b2tlbiA9ICcnO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhBZGFwdGVyLmxvZ291dChhZGFwdGVyT3B0aW9ucykuZG9uZShyZW1vdmVDb29raWVGbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGV4aXN0aW5nIHVzZXIgYWNjZXNzIHRva2VuIGlmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluLiBPdGhlcndpc2UsIGxvZ3MgdGhlIHVzZXIgaW4sIGNyZWF0aW5nIGEgbmV3IHVzZXIgYWNjZXNzIHRva2VuLCBhbmQgcmV0dXJucyB0aGUgbmV3IHRva2VuLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBhdXRoTWdyLmdldFRva2VuKClcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coJ015IHRva2VuIGlzICcsIHRva2VuKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgaWYgKHRva2VuKSB7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKHRva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICogICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKylcbiAgICAgKiAgICAgICAgICAgICAgICAgIHsgY29uc29sZS5sb2coZ3JvdXBzW2ldLm5hbWUpOyB9XG4gICAgICogICAgICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIHBhcnRpY3VsYXIgdXNlclxuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHt1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB0b2tlbjogc2F2ZWRQcm9qQWNjZXNzVG9rZW4gfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcGFyYW1zYCBPYmplY3Qgd2l0aCBhIHVzZXJJZCBhbmQgdG9rZW4gcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSB1c2VySWQuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBPdGhlcndpc2UsIHBhc3MgYSBzdHJpbmcuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGBwYXJhbXMudG9rZW5gIFRoZSBhdXRob3JpemF0aW9uIGNyZWRlbnRpYWxzIChhY2Nlc3MgdG9rZW4pIHRvIHVzZSBmb3IgY2hlY2tpbmcgdGhlIGdyb3VwcyBmb3IgdGhpcyB1c2VyLiBJZiBsb29raW5nIHVwIGdyb3VwcyBmb3IgdGhlIGN1cnJlbnRseSBsb2dnZWQgaW4gdXNlciwgdGhpcyBpcyBpbiB0aGUgc2Vzc2lvbiBpbmZvcm1hdGlvbi4gQSB0ZWFtIG1lbWJlcidzIHRva2VuIG9yIGEgcHJvamVjdCBhY2Nlc3MgdG9rZW4gY2FuIGFjY2VzcyBhbGwgdGhlIGdyb3VwcyBmb3IgYWxsIGVuZCB1c2VycyBpbiB0aGUgdGVhbSBvciBwcm9qZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKi9cbiAgICBnZXRVc2VyR3JvdXBzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHsgc3VjY2VzczogJC5ub29wIH0sIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAobWVtYmVySW5mbykge1xuICAgICAgICAgICAgLy8gVGhlIG1lbWJlciBBUEkgaXMgYXQgdGhlIGFjY291bnQgc2NvcGUsIHdlIGZpbHRlciBieSBwcm9qZWN0XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICAgICAgICAgIG1lbWJlckluZm8gPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBncm91cC5wcm9qZWN0ID09PSBhZGFwdGVyT3B0aW9ucy5wcm9qZWN0O1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRTdWNjZXNzLmFwcGx5KHRoaXMsIFttZW1iZXJJbmZvXSk7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKG1lbWJlckluZm8pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBtZW1iZXJBZGFwdGVyID0gbmV3IE1lbWJlckFkYXB0ZXIoeyB0b2tlbjogcGFyYW1zLnRva2VuIH0pO1xuICAgICAgICBtZW1iZXJBZGFwdGVyLmdldEdyb3Vwc0ZvclVzZXIocGFyYW1zLCBhZGFwdGVyT3B0aW9ucykuZmFpbCgkZC5yZWplY3QpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHNlc3Npb24gaW5mb3JtYXRpb24gZm9yIHRoZSBjdXJyZW50IHVzZXIsIGluY2x1ZGluZyB0aGUgYHVzZXJJZGAsIGBhY2NvdW50YCwgYHByb2plY3RgLCBgZ3JvdXBJZGAsIGBncm91cE5hbWVgLCBgaXNGYWNgICh3aGV0aGVyIHRoZSBlbmQgdXNlciBpcyBhIGZhY2lsaXRhdG9yIG9mIHRoaXMgZ3JvdXApLCBhbmQgYGF1dGhfdG9rZW5gICh1c2VyIGFjY2VzcyB0b2tlbikuXG4gICAgICpcbiAgICAgKiAqSW1wb3J0YW50KjogVGhpcyBtZXRob2QgaXMgc3luY2hyb25vdXMuIFRoZSBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHJldHVybmVkIGltbWVkaWF0ZWx5IGluIGFuIG9iamVjdDsgbm8gY2FsbGJhY2tzIG9yIHByb21pc2VzIGFyZSBuZWVkZWQuXG4gICAgICpcbiAgICAgKiBCeSBkZWZhdWx0LCBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHN0b3JlZCBpbiBhIGNvb2tpZSBpbiB0aGUgYnJvd3Nlci4gWW91IGNhbiBjaGFuZ2UgdGhpcyB3aXRoIHRoZSBgc3RvcmVgIGNvbmZpZ3VyYXRpb24gb3B0aW9uLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm86IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiBnZXRTZXNzaW9uKHRoaXMuc3RvcmUsIG9wdGlvbnMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEF1dGhNYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2hhbm5lbCA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlJyk7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgYXJvdW5kIHRoZSBkZWZhdWx0IFtjb21ldGQgSmF2YVNjcmlwdCBsaWJyYXJ5XShodHRwOi8vZG9jcy5jb21ldGQub3JnLzIvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCksIGAkLmNvbWV0ZGAuIEl0IHByb3ZpZGVzIGEgZmV3IG5pY2UgZmVhdHVyZXMgdGhhdCBgJC5jb21ldGRgIGRvZXNuJ3QsIGluY2x1ZGluZzpcbiAqXG4gKiAqIEF1dG9tYXRpYyByZS1zdWJzY3JpcHRpb24gdG8gY2hhbm5lbHMgaWYgeW91IGxvc2UgeW91ciBjb25uZWN0aW9uXG4gKiAqIE9ubGluZSAvIE9mZmxpbmUgbm90aWZpY2F0aW9uc1xuICogKiAnRXZlbnRzJyBmb3IgY29tZXRkIG5vdGlmaWNhdGlvbnMgKGluc3RlYWQgb2YgaGF2aW5nIHRvIGxpc3RlbiBvbiBzcGVjaWZpYyBtZXRhIGNoYW5uZWxzKVxuICpcbiAqIFdoaWxlIHlvdSBjYW4gd29yayBkaXJlY3RseSB3aXRoIHRoZSBDaGFubmVsIE1hbmFnZXIgdGhyb3VnaCBOb2RlLmpzIChmb3IgZXhhbXBsZSwgYHJlcXVpcmUoJ21hbmFnZXIvY2hhbm5lbC1tYW5hZ2VyJylgKSAtLSBvciBldmVuIHdvcmsgZGlyZWN0bHkgd2l0aCBgJC5jb21ldGRgIGFuZCBFcGljZW50ZXIncyB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIC0tIG1vc3Qgb2Z0ZW4gaXQgd2lsbCBiZSBlYXNpZXN0IHRvIHdvcmsgd2l0aCB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKS4gVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIHRoYXQgaW5zdGFudGlhdGVzIGEgQ2hhbm5lbCBNYW5hZ2VyIHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgTWFuYWdlci4gKFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLilcbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgTWFuYWdlciBpbiBjbGllbnQtc2lkZSBKYXZhU2NyaXB0LCBpbnN0YW50aWF0ZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSwgZ2V0IHRoZSBjaGFubmVsLCB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gKlxuICogICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAqICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgTWFuYWdlci4gQmVzaWRlcyB0aGUgY29tbW9uIG9wdGlvbnMgbGlzdGVkIGhlcmUsIHNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIG90aGVyIHN1cHBvcnRlZCBvcHRpb25zLlxuICogKiBgb3B0aW9ucy51cmxgIFRoZSBDb21ldGQgZW5kcG9pbnQgVVJMLlxuICogKiBgb3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkYCBXaGV0aGVyIHdlYnNvY2tldCBzdXBwb3J0IGlzIGFjdGl2ZSAoYm9vbGVhbikuXG4gKiAqIGBvcHRpb25zLmNoYW5uZWxgIE90aGVyIGRlZmF1bHRzIHRvIHBhc3Mgb24gdG8gaW5zdGFuY2VzIG9mIHRoZSB1bmRlcmx5aW5nIENoYW5uZWwgU2VydmljZS4gU2VlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pIGZvciBkZXRhaWxzLlxuICpcbiAqL1xudmFyIENoYW5uZWxNYW5hZ2VyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICBpZiAoISQuY29tZXRkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tZXRkIGxpYnJhcnkgbm90IGZvdW5kLiBQbGVhc2UgaW5jbHVkZSBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy51cmwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhbiB1cmwgZm9yIHRoZSBjb21ldGQgc2VydmVyJyk7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbG9nIGxldmVsIGZvciB0aGUgY2hhbm5lbCAobG9ncyB0byBjb25zb2xlKS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGxvZ0xldmVsOiAnaW5mbycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlLiBEZWZhdWx0cyB0byBgZmFsc2VgOyBFcGljZW50ZXIgZG9lc24ndCBjdXJyZW50bHkgc3VwcG9ydCBjb21tdW5pY2F0aW9uIHRocm91Z2ggd2Vic29ja2V0cy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICB3ZWJzb2NrZXRFbmFibGVkOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogSWYgZmFsc2UgZWFjaCBpbnN0YW5jZSBvZiBDaGFubmVsIHdpbGwgaGF2ZSBhIHNlcGFyYXRlIGNvbWV0ZCBjb25uZWN0aW9uIHRvIHNlcnZlciwgd2hpY2ggY291bGQgYmUgbm9pc3kuIFNldCB0byB0cnVlIHRvIHJlLXVzZSB0aGUgc2FtZSBjb25uZWN0aW9uIGFjcm9zcyBpbnN0YW5jZXMuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2hhcmVDb25uZWN0aW9uOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLyksIHdoaWNoIGFyZSBjcmVhdGVkIHRocm91Z2ggYGdldENoYW5uZWwoKWAuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBjaGFubmVsOiB7XG5cbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMgPSBbXTtcbiAgICB0aGlzLm9wdGlvbnMgPSBkZWZhdWx0Q29tZXRPcHRpb25zO1xuXG4gICAgaWYgKGRlZmF1bHRDb21ldE9wdGlvbnMuc2hhcmVDb25uZWN0aW9uICYmIENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkKSB7XG4gICAgICAgIHRoaXMuY29tZXRkID0gQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQ7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICB2YXIgY29tZXRkID0gbmV3ICQuQ29tZXRkKCk7XG4gICAgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQgPSBjb21ldGQ7XG5cbiAgICBjb21ldGQud2Vic29ja2V0RW5hYmxlZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMud2Vic29ja2V0RW5hYmxlZDtcblxuICAgIHRoaXMuaXNDb25uZWN0ZWQgPSBmYWxzZTtcbiAgICB2YXIgY29ubmVjdGlvbkJyb2tlbiA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignZGlzY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIGNvbm5lY3Rpb25TdWNjZWVkZWQgPSBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIoJ2Nvbm5lY3QnLCBtZXNzYWdlKTtcbiAgICB9O1xuICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICBjb21ldGQuY29uZmlndXJlKGRlZmF1bHRDb21ldE9wdGlvbnMpO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9jb25uZWN0JywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgdmFyIHdhc0Nvbm5lY3RlZCA9IHRoaXMuaXNDb25uZWN0ZWQ7XG4gICAgICAgIHRoaXMuaXNDb25uZWN0ZWQgPSAobWVzc2FnZS5zdWNjZXNzZnVsID09PSB0cnVlKTtcbiAgICAgICAgaWYgKCF3YXNDb25uZWN0ZWQgJiYgdGhpcy5pc0Nvbm5lY3RlZCkgeyAvL0Nvbm5lY3RpbmcgZm9yIHRoZSBmaXJzdCB0aW1lXG4gICAgICAgICAgICBjb25uZWN0aW9uU3VjY2VlZGVkLmNhbGwodGhpcywgbWVzc2FnZSk7XG4gICAgICAgIH0gZWxzZSBpZiAod2FzQ29ubmVjdGVkICYmICF0aGlzLmlzQ29ubmVjdGVkKSB7IC8vT25seSB0aHJvdyBkaXNjb25uZWN0ZWQgbWVzc2FnZSBmcm8gdGhlIGZpcnN0IGRpc2Nvbm5lY3QsIG5vdCBvbmNlIHBlciB0cnlcbiAgICAgICAgICAgIGNvbm5lY3Rpb25Ccm9rZW4uY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH0uYmluZCh0aGlzKSk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Rpc2Nvbm5lY3QnLCBjb25uZWN0aW9uQnJva2VuKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvaGFuZHNoYWtlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgaWYgKG1lc3NhZ2Uuc3VjY2Vzc2Z1bCkge1xuICAgICAgICAgICAgLy9odHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0X3N1YnNjcmliZS5odG1sI2phdmFzY3JpcHRfc3Vic2NyaWJlX21ldGFfY2hhbm5lbHNcbiAgICAgICAgICAgIC8vIF4gXCJkeW5hbWljIHN1YnNjcmlwdGlvbnMgYXJlIGNsZWFyZWQgKGxpa2UgYW55IG90aGVyIHN1YnNjcmlwdGlvbikgYW5kIHRoZSBhcHBsaWNhdGlvbiBuZWVkcyB0byBmaWd1cmUgb3V0IHdoaWNoIGR5bmFtaWMgc3Vic2NyaXB0aW9uIG11c3QgYmUgcGVyZm9ybWVkIGFnYWluXCJcbiAgICAgICAgICAgIGNvbWV0ZC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgJChtZS5jdXJyZW50U3Vic2NyaXB0aW9ucykuZWFjaChmdW5jdGlvbiAoaW5kZXgsIHN1YnMpIHtcbiAgICAgICAgICAgICAgICAgICAgY29tZXRkLnJlc3Vic2NyaWJlKHN1YnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vT3RoZXIgaW50ZXJlc3RpbmcgZXZlbnRzIGZvciByZWZlcmVuY2VcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3N1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3N1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWJzY3JpYmUnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCd1bnN1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvcHVibGlzaCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3B1Ymxpc2gnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3Vuc3VjY2Vzc2Z1bCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ2Vycm9yJywgbWVzc2FnZSk7XG4gICAgfSk7XG5cbiAgICBjb21ldGQuaGFuZHNoYWtlKCk7XG5cbiAgICB0aGlzLmNvbWV0ZCA9IGNvbWV0ZDtcbn07XG5cblxuQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgIHZhciBjaGFubmVsID0gY20uZ2V0Q2hhbm5lbCgpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvL0lmIHlvdSBqdXN0IHdhbnQgdG8gcGFzcyBpbiBhIHN0cmluZ1xuICAgICAgICBpZiAob3B0aW9ucyAmJiAhJC5pc1BsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAgICAgdHJhbnNwb3J0OiB0aGlzLmNvbWV0ZFxuICAgICAgICB9O1xuICAgICAgICB2YXIgY2hhbm5lbCA9IG5ldyBDaGFubmVsKCQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLm9wdGlvbnMuY2hhbm5lbCwgZGVmYXVsdHMsIG9wdGlvbnMpKTtcblxuXG4gICAgICAgIC8vV3JhcCBzdWJzIGFuZCB1bnN1YnMgc28gd2UgY2FuIHVzZSBpdCB0byByZS1hdHRhY2ggaGFuZGxlcnMgYWZ0ZXIgYmVpbmcgZGlzY29ubmVjdGVkXG4gICAgICAgIHZhciBzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHN1YmlkID0gc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyAgPSB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmNvbmNhdChzdWJpZCk7XG4gICAgICAgICAgICByZXR1cm4gc3ViaWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuXG4gICAgICAgIHZhciB1bnN1YnMgPSBjaGFubmVsLnVuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnVuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJlbW92ZWQgPSB1bnN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zW2ldLmlkID09PSByZW1vdmVkLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZW1vdmVkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlclxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIChtb3JlIGdlbmVyaWMpIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pLCB0byBpbnN0YW50aWF0ZSBpdCB3aXRoIEVwaWNlbnRlci1zcGVjaWZpYyBkZWZhdWx0cy4gSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGluY2x1ZGluZyBhIG5vdGlmaWNhdGlvbiBvciBjaGF0IGZlYXR1cmUgaW4geW91ciBwcm9qZWN0LCB1c2luZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIHByb2JhYmx5IHRoZSBlYXNpZXN0IHdheSB0byBnZXQgc3RhcnRlZC5cbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXI6IGluc3RhbnRpYXRlIGl0LCBnZXQgdGhlIGNoYW5uZWwgb2YgdGhlIHNjb3BlIHlvdSB3YW50IChbdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLCBvciBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpKSwgdGhlbiB1c2UgdGhlIGNoYW5uZWwncyBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIHN1YnNjcmliZSB0byB0b3BpY3Mgb3IgcHVibGlzaCBkYXRhIHRvIHRvcGljcy5cbiAqXG4gKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAqXG4gKiBGb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIEVwaWNlbnRlcidzIHB1c2ggY2hhbm5lbCwgc2VlIHRoZSBpbnRyb2R1Y3Rvcnkgbm90ZXMgb24gdGhlIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIHBhZ2UuXG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYHNlcnZlcmAgT2JqZWN0IHdpdGggZGV0YWlscyBhYm91dCB0aGUgRXBpY2VudGVyIHByb2plY3QgZm9yIHRoaXMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbnN0YW5jZS5cbiAqICogYHNlcnZlci5hY2NvdW50YCBUaGUgRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgc2VydmVyLnByb2plY3RgIEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICovXG5cbnZhciBDaGFubmVsTWFuYWdlciA9IHJlcXVpcmUoJy4vY2hhbm5lbC1tYW5hZ2VyJyk7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgdXJsU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlJyk7XG5cbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBzZXNzaW9uID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG52YXIgZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvciA9IGZ1bmN0aW9uICh2YWx1ZSwgc2Vzc2lvbktleU5hbWUsIHNldHRpbmdzKSB7XG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgaWYgKHNldHRpbmdzICYmIHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXSkge1xuICAgICAgICAgICAgdmFsdWUgPSBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV07XG4gICAgICAgIH0gZWxzZSBpZiAodXNlckluZm9bc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHVzZXJJbmZvW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihzZXNzaW9uS2V5TmFtZSArICcgbm90IGZvdW5kLiBQbGVhc2UgbG9nLWluIGFnYWluLCBvciBzcGVjaWZ5ICcgKyBzZXNzaW9uS2V5TmFtZSArICcgZXhwbGljaXRseScpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbn07XG52YXIgX19zdXBlciA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZTtcbnZhciBFcGljZW50ZXJDaGFubmVsTWFuYWdlciA9IGNsYXNzRnJvbShDaGFubmVsTWFuYWdlciwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcblxuICAgICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgICAgICBhY2NvdW50OiB1c2VySW5mby5hY2NvdW50LFxuICAgICAgICAgICAgcHJvamVjdDogdXNlckluZm8ucHJvamVjdCxcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIHVzZXJJbmZvLCBvcHRpb25zKTtcblxuICAgICAgICB2YXIgdXJsT3B0cyA9IHVybFNlcnZpY2UoZGVmYXVsdENvbWV0T3B0aW9ucy5zZXJ2ZXIpO1xuICAgICAgICBpZiAoIWRlZmF1bHRDb21ldE9wdGlvbnMudXJsKSB7XG4gICAgICAgICAgICAvL0RlZmF1bHQgZXBpY2VudGVyIGNvbWV0ZCBlbmRwb2ludFxuICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy51cmwgPSB1cmxPcHRzLnByb3RvY29sICsgJzovLycgKyB1cmxPcHRzLmhvc3QgKyAnL2NoYW5uZWwvc3Vic2NyaWJlJztcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgZGVmYXVsdENvbWV0T3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBnaXZlbiBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLiBUaGUgZ3JvdXAgbXVzdCBleGlzdCBpbiB0aGUgYWNjb3VudCAodGVhbSkgYW5kIHByb2plY3QgcHJvdmlkZWQuXG4gICAgICpcbiAgICAgKiBUaGVyZSBhcmUgbm8gbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWw7IGFsbCBtZXNzYWdlcyBhcmUgdXNlci1vcmlnaW5hdGVkLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJ2Jyb2FkY2FzdHMnLCBjYWxsYmFjayk7XG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBHcm91cCB0byBicm9hZGNhc3QgdG8uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldEdyb3VwQ2hhbm5lbDogZnVuY3Rpb24gKGdyb3VwTmFtZSkge1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScpO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2dyb3VwJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lXS5qb2luKCcvJyk7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICogICAgICAgICBydW46IHsgbW9kZWw6ICdtb2RlbC5lcW4nIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICogICAgIHdvcmxkTWFuYWdlci5nZXRDdXJyZW50V29ybGQoKS50aGVuKGZ1bmN0aW9uICh3b3JsZE9iamVjdCwgd29ybGRBZGFwdGVyKSB7XG4gICAgICogICAgICAgICB2YXIgd29ybGRDaGFubmVsID0gY20uZ2V0V29ybGRDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHdvcmxkQ2hhbm5lbC5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICogICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICogICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFRoZSB3b3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFdvcmxkQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCBncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHdvcmxkaWQgPSAoJC5pc1BsYWluT2JqZWN0KHdvcmxkKSAmJiB3b3JsZC5pZCkgPyB3b3JsZC5pZCA6IHdvcmxkO1xuICAgICAgICBpZiAoIXdvcmxkaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgYSB3b3JsZCBpZCcpO1xuICAgICAgICB9XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJyk7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvd29ybGQnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgY3VycmVudCBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaW4gdGhhdCB1c2VyJ3MgY3VycmVudCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS4gTm90ZSB0aGF0IHRoaXMgY2hhbm5lbCBvbmx5IGdldHMgbm90aWZpY2F0aW9ucyBmb3Igd29ybGRzIGN1cnJlbnRseSBpbiBtZW1vcnkuIChTZWUgbW9yZSBiYWNrZ3JvdW5kIG9uIFtwZXJzaXN0ZW5jZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlKS4pXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB1c2VyQ2hhbm5lbCA9IGNtLmdldFVzZXJDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHVzZXJDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFVzZXJDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXIsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVzZXJpZCA9ICgkLmlzUGxhaW5PYmplY3QodXNlcikgJiYgdXNlci5pZCkgPyB1c2VyLmlkIDogdXNlcjtcbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkLCB1c2VyaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIHRoYXQgYXV0b21hdGljYWxseSB0cmFja3MgdGhlIHByZXNlbmNlIG9mIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhhdCBpcywgd2hldGhlciB0aGUgZW5kIHVzZXIgaXMgY3VycmVudGx5IG9ubGluZSBpbiB0aGlzIGdyb3VwIGFuZCB3b3JsZC4gTm90aWZpY2F0aW9ucyBhcmUgYXV0b21hdGljYWxseSBzZW50IHdoZW4gdGhlIGVuZCB1c2VyIGNvbWVzIG9ubGluZSwgYW5kIHdoZW4gdGhlIGVuZCB1c2VyIGdvZXMgb2ZmbGluZSAobm90IHByZXNlbnQgZm9yIG1vcmUgdGhhbiAyIG1pbnV0ZXMpLiBVc2VmdWwgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZm9yIGxldHRpbmcgZWFjaCBlbmQgdXNlciBrbm93IHdoZXRoZXIgb3RoZXIgdXNlcnMgaW4gdGhlaXIgc2hhcmVkIHdvcmxkIGFyZSBhbHNvIG9ubGluZS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIG1vZGVsOiAnbW9kZWwuZXFuJ1xuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZFNlcnZpY2UpIHtcbiAgICAgKiAgICAgICAgIHZhciBwcmVzZW5jZUNoYW5uZWwgPSBjbS5nZXRQcmVzZW5jZUNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgcHJlc2VuY2VDaGFubmVsLm9uKCdwcmVzZW5jZScsIGZ1bmN0aW9uIChldnQsIG5vdGlmaWNhdGlvbikge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZyhub3RpZmljYXRpb24ub25saW5lLCBub3RpZmljYXRpb24udXNlcklkKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB3b3JsZGAgV29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB1c2VyaWRgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFByZXNlbmNlQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCB1c2VyaWQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgdmFyIGxhc3RQaW5nVGltZSA9IHsgfTtcblxuICAgICAgICB2YXIgUElOR19JTlRFUlZBTCA9IDYwMDA7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCdpbnRlcm5hbC1waW5nLWNoYW5uZWwnLCBmdW5jdGlvbiAobm90aWZpY2F0aW9uKSB7XG4gICAgICAgICAgICB2YXIgaW5jb21pbmdVc2VySWQgPSBub3RpZmljYXRpb24uZGF0YS51c2VyO1xuICAgICAgICAgICAgaWYgKCFsYXN0UGluZ1RpbWVbaW5jb21pbmdVc2VySWRdICYmIGluY29taW5nVXNlcklkICE9PSB1c2VyaWQpIHtcbiAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDogaW5jb21pbmdVc2VySWQsIG9ubGluZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIHsgdXNlcjogdXNlcmlkIH0pO1xuXG4gICAgICAgICAgICAkLmVhY2gobGFzdFBpbmdUaW1lLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBub3cgPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSAmJiB2YWx1ZSArIChQSU5HX0lOVEVSVkFMICogMikgPCBub3cpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2tleV0gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDoga2V5LCBvbmxpbmU6IGZhbHNlIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBQSU5HX0lOVEVSVkFMKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIGNvbGxlY3Rpb24uIChUaGUgY29sbGVjdGlvbiBuYW1lIGlzIHNwZWNpZmllZCBpbiB0aGUgYHJvb3RgIGFyZ3VtZW50IHdoZW4gdGhlIFtEYXRhIFNlcnZpY2VdKC4uL2RhdGEtYXBpLXNlcnZpY2UvKSBpcyBpbnN0YW50aWF0ZWQuKSBNdXN0IGJlIG9uZSBvZiB0aGUgY29sbGVjdGlvbnMgaW4gdGhpcyBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBhdXRvbWF0aWMgbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWwgd2hlbiBkYXRhIGlzIGNyZWF0ZWQsIHVwZGF0ZWQsIG9yIGRlbGV0ZWQgaW4gdGhpcyBjb2xsZWN0aW9uLiBTZWUgbW9yZSBvbiBbYXV0b21hdGljIG1lc3NhZ2VzIHRvIHRoZSBkYXRhIGNoYW5uZWxdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNkYXRhLW1lc3NhZ2VzKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZ2MgPSBjbS5nZXREYXRhQ2hhbm5lbCgnc3VydmV5LXJlc3BvbnNlcycpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEsIG1ldGEpIHtcbiAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIG1ldGEuZGF0ZSBpcyB0aW1lIG9mIGNoYW5nZSxcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnN1YlR5cGUgaXMgdGhlIGtpbmQgb2YgY2hhbmdlOiBuZXcsIHVwZGF0ZSwgb3IgZGVsZXRlXG4gICAgICogICAgICAgICAgLy8gbWV0YS5wYXRoIGlzIHRoZSBmdWxsIHBhdGggdG8gdGhlIGNoYW5nZWQgZGF0YVxuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKG1ldGEpO1xuICAgICAqICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgY29sbGVjdGlvbmAgTmFtZSBvZiBjb2xsZWN0aW9uIHdob3NlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIHlvdSB3YW50IHRvIHJlY2VpdmUuXG4gICAgICovXG4gICAgZ2V0RGF0YUNoYW5uZWw6IGZ1bmN0aW9uIChjb2xsZWN0aW9uKSB7XG4gICAgICAgIGlmICghY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIGNvbGxlY3Rpb24gdG8gbGlzdGVuIG9uLicpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2RhdGEnLCBhY2NvdW50LCBwcm9qZWN0LCBjb2xsZWN0aW9uXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgLy9UT0RPOiBGaXggYWZ0ZXIgRXBpY2VudGVyIGJ1ZyBpcyByZXNvbHZlZFxuICAgICAgICB2YXIgb2xkc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjYWxsYmFja1dpdGhDbGVhbkRhdGEgPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgICAgICAgICAgICAgIHZhciBtZXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYXlsb2FkLmNoYW5uZWwsXG4gICAgICAgICAgICAgICAgICAgIHN1YlR5cGU6IHBheWxvYWQuZGF0YS5zdWJUeXBlLFxuICAgICAgICAgICAgICAgICAgICBkYXRlOiBwYXlsb2FkLmRhdGEuZGF0ZVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGFjdHVhbERhdGEgPSBwYXlsb2FkLmRhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICBpZiAoYWN0dWFsRGF0YS5kYXRhKSB7IC8vRGVsZXRlIG5vdGlmaWNhdGlvbnMgYXJlIG9uZSBkYXRhLWxldmVsIGJlaGluZCBvZiBjb3Vyc2VcbiAgICAgICAgICAgICAgICAgICAgYWN0dWFsRGF0YSA9IGFjdHVhbERhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIGFjdHVhbERhdGEsIG1ldGEpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aENsZWFuRGF0YSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVQSV9DT09LSUVfS0VZOiAnZXBpY2VudGVyLnByb2plY3QudG9rZW4nLFxuICAgIEVQSV9TRVNTSU9OX0tFWTogJ2VwaWNlbnRlci51c2VyLnNlc3Npb24nLFxuICAgIFNUUkFURUdZX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLXNjZW5hcmlvJ1xufTsiLCIvKipcbiogIyMgUnVuIE1hbmFnZXJcbipcbiogVGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBhY2Nlc3MgdG8gcnVucyBmb3IgeW91ciBwcm9qZWN0LiBUaGlzIGFsbG93cyB5b3UgdG8gcmVhZCBhbmQgdXBkYXRlIHZhcmlhYmxlcywgY2FsbCBvcGVyYXRpb25zLCBldGMuIEFkZGl0aW9uYWxseSwgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLiBTcGVjaWZpY2FsbHksIHlvdSBjYW4gc2VsZWN0IFtydW4gY3JlYXRpb24gc3RyYXRlZ2llcyAocnVsZXMpXSguLi8uLi9zdHJhdGVneS8pIGZvciB3aGljaCBydW5zIGVuZCB1c2VycyBvZiB5b3VyIHByb2plY3Qgd29yayB3aXRoIHdoZW4gdGhleSBsb2cgaW4gdG8geW91ciBwcm9qZWN0LlxuKlxuKiBUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGNyZWF0ZSBuZXcgcnVucywgaW5jbHVkaW5nIHRoZSBFcGljZW50ZXIuanMgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSwgdGhlIFJFU0ZUZnVsIFtSdW4gQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkpIGFuZCB0aGUgW01vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLykuIEhvd2V2ZXIsIGZvciBzb21lIHByb2plY3RzIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gcGljayB1cCB3aGVyZSB0aGUgdXNlciBsZWZ0IG9mZiwgdXNpbmcgYW4gZXhpc3RpbmcgcnVuLiBBbmQgaW4gc29tZSBwcm9qZWN0cywgd2hldGhlciB0byBjcmVhdGUgYSBuZXcgcnVuIG9yIHVzZSBhbiBleGlzdGluZyBvbmUgaXMgY29uZGl0aW9uYWwsIGZvciBleGFtcGxlIGJhc2VkIG9uIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZXhpc3RpbmcgcnVuIG9yIHlvdXIgb3duIGtub3dsZWRnZSBhYm91dCB0aGUgbW9kZWwuIFRoZSBSdW4gTWFuYWdlciBwcm92aWRlcyB0aGlzIGxldmVsIG9mIGNvbnRyb2w6IHlvdXIgY2FsbCB0byBgZ2V0UnVuKClgLCByYXRoZXIgdGhhbiBhbHdheXMgcmV0dXJuaW5nIGEgbmV3IHJ1biwgcmV0dXJucyBhIHJ1biBiYXNlZCBvbiB0aGUgc3RyYXRlZ3kgeW91J3ZlIHNwZWNpZmllZC4gKE5vdGUgdGhhdCBtYW55IG9mIHRoZSBFcGljZW50ZXIgc2FtcGxlIHByb2plY3RzIHVzZSBhIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LCBiZWNhdXNlIGdlbmVyYWxseSB0aGUgc2FtcGxlIHByb2plY3RzIGFyZSBwbGF5ZWQgaW4gb25lIGVuZCB1c2VyIHNlc3Npb24gYW5kIGRvbid0IGNhcmUgYWJvdXQgcnVuIHN0YXRlcyBvciBydW4gc3RyYXRlZ2llcy4pXG4qXG4qXG4qICMjIyBVc2luZyB0aGUgUnVuIE1hbmFnZXIgdG8gY3JlYXRlIGFuZCBhY2Nlc3MgcnVuc1xuKlxuKiBUbyB1c2UgdGhlIFJ1biBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuKlxuKiAgICogYHJ1bmA6IChyZXF1aXJlZCkgUnVuIG9iamVjdC4gTXVzdCBjb250YWluOlxuKiAgICAgICAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICAgICAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4qICAgICAgICogYG1vZGVsYDogVGhlIG5hbWUgb2YgeW91ciBwcmltYXJ5IG1vZGVsIGZpbGUuIChTZWUgbW9yZSBvbiBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4pXG4qICAgICAgICogYHNjb3BlYDogKG9wdGlvbmFsKSBTY29wZSBvYmplY3QgZm9yIHRoZSBydW4sIGZvciBleGFtcGxlIGBzY29wZS5ncm91cGAgd2l0aCB2YWx1ZSBvZiB0aGUgbmFtZSBvZiB0aGUgZ3JvdXAuXG4qICAgICAgICogYHNlcnZlcmA6IChvcHRpb25hbCkgQW4gb2JqZWN0IHdpdGggb25lIGZpZWxkLCBgaG9zdGAuIFRoZSB2YWx1ZSBvZiBgaG9zdGAgaXMgdGhlIHN0cmluZyBgYXBpLmZvcmlvLmNvbWAsIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4qICAgICAgICogYGZpbGVzYDogKG9wdGlvbmFsKSBJZiBhbmQgb25seSBpZiB5b3UgYXJlIHVzaW5nIGEgVmVuc2ltIG1vZGVsIGFuZCB5b3UgaGF2ZSBhZGRpdGlvbmFsIGRhdGEgdG8gcGFzcyBpbiB0byB5b3VyIG1vZGVsLCB5b3UgY2FuIHBhc3MgYSBgZmlsZXNgIG9iamVjdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgZmlsZXMsIGZvciBleGFtcGxlOiBgXCJmaWxlc1wiOiB7XCJkYXRhXCI6IFwibXlFeHRyYURhdGEueGxzXCJ9YC4gKE5vdGUgdGhhdCB5b3UnbGwgYWxzbyBuZWVkIHRvIGFkZCB0aGlzIHNhbWUgZmlsZXMgb2JqZWN0IHRvIHlvdXIgVmVuc2ltIFtjb25maWd1cmF0aW9uIGZpbGVdKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltLykuKSBTZWUgdGhlIFt1bmRlcmx5aW5nIE1vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLyNwb3N0LWNyZWF0aW5nLWEtbmV3LXJ1bi1mb3ItdGhpcy1wcm9qZWN0KSBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbi5cbipcbiogICAqIGBzdHJhdGVneWA6IChvcHRpb25hbCkgUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4qXG4qICAgKiBgc2Vzc2lvbktleWA6IChvcHRpb25hbCkgTmFtZSBvZiBicm93c2VyIGNvb2tpZSBpbiB3aGljaCB0byBzdG9yZSBydW4gaW5mb3JtYXRpb24sIGluY2x1ZGluZyBydW4gaWQuIE1hbnkgY29uZGl0aW9uYWwgc3RyYXRlZ2llcywgaW5jbHVkaW5nIHRoZSBwcm92aWRlZCBzdHJhdGVnaWVzLCByZWx5IG9uIHRoaXMgYnJvd3NlciBjb29raWUgdG8gc3RvcmUgdGhlIHJ1biBpZCBhbmQgaGVscCBtYWtlIHRoZSBkZWNpc2lvbiBvZiB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZS4gVGhlIG5hbWUgb2YgdGhpcyBjb29raWUgZGVmYXVsdHMgdG8gYGVwaWNlbnRlci1zY2VuYXJpb2AgYW5kIGNhbiBiZSBzZXQgd2l0aCB0aGUgYHNlc3Npb25LZXlgIHBhcmFtZXRlci5cbipcbipcbiogQWZ0ZXIgaW5zdGFudGlhdGluZyBhIFJ1biBNYW5hZ2VyLCBtYWtlIGEgY2FsbCB0byBgZ2V0UnVuKClgIHdoZW5ldmVyIHlvdSBuZWVkIHRvIGFjY2VzcyBhIHJ1biBmb3IgdGhpcyBlbmQgdXNlci4gVGhlIGBSdW5NYW5hZ2VyLnJ1bmAgY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLiBUaGUgUnVuIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBhY2Nlc3MgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy5cbipcbiogKipFeGFtcGxlKipcbipcbiogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiogICAgICAgICAgIHJ1bjoge1xuKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJyxcbiogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiogICAgICAgICAgIH0sXG4qICAgICAgICAgICBzdHJhdGVneTogJ2Fsd2F5cy1uZXcnLFxuKiAgICAgICAgICAgc2Vzc2lvbktleTogJ2VwaWNlbnRlci1zZXNzaW9uJ1xuKiAgICAgICB9KTtcbiogICAgICAgcm0uZ2V0UnVuKClcbiogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuKiAgICAgICAgICAgICAgIC8vIHRoZSByZXR1cm4gdmFsdWUgb2YgZ2V0UnVuKCkgaXMgYSBydW4gb2JqZWN0XG4qICAgICAgICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gYWxzbyBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuKiAgICAgICAgICAgICAgIC8vIHNvIGFueSBSdW4gU2VydmljZSBtZXRob2QgaXMgdmFsaWQgaGVyZVxuKiAgICAgICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiogICAgICAgfSlcbipcbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBzdHJhdGVnaWVzTWFwID0gcmVxdWlyZSgnLi9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcCcpO1xudmFyIHNwZWNpYWxPcGVyYXRpb25zID0gcmVxdWlyZSgnLi9zcGVjaWFsLW9wZXJhdGlvbnMnKTtcbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcblxuXG5mdW5jdGlvbiBwYXRjaFJ1blNlcnZpY2Uoc2VydmljZSwgbWFuYWdlcikge1xuICAgIGlmIChzZXJ2aWNlLnBhdGNoZWQpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuXG4gICAgdmFyIG9yaWcgPSBzZXJ2aWNlLmRvO1xuICAgIHNlcnZpY2UuZG8gPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHJlc2VydmVkT3BzID0gT2JqZWN0LmtleXMoc3BlY2lhbE9wZXJhdGlvbnMpO1xuICAgICAgICBpZiAocmVzZXJ2ZWRPcHMuaW5kZXhPZihvcGVyYXRpb24pID09PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG9yaWcuYXBwbHkoc2VydmljZSwgYXJndW1lbnRzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT3BlcmF0aW9uc1tvcGVyYXRpb25dLmNhbGwoc2VydmljZSwgcGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBzZXJ2aWNlLnBhdGNoZWQgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHNlcnZpY2U7XG59XG5cblxuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cblxuICAgIHN0cmF0ZWd5OiAnbmV3LWlmLWluaXRpYWxpemVkJ1xufTtcblxuZnVuY3Rpb24gUnVuTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMucnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICB0aGlzLnJ1biA9IHRoaXMub3B0aW9ucy5ydW47XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5ydW4gPSBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMucnVuKTtcbiAgICB9XG5cbiAgICBwYXRjaFJ1blNlcnZpY2UodGhpcy5ydW4sIHRoaXMpO1xuXG4gICAgdmFyIFN0cmF0ZWd5Q3RvciA9IHR5cGVvZiB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgPT09ICdmdW5jdGlvbicgPyB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgOiBzdHJhdGVnaWVzTWFwW3RoaXMub3B0aW9ucy5zdHJhdGVneV07XG5cbiAgICBpZiAoIVN0cmF0ZWd5Q3Rvcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NwZWNpZmllZCBydW4gY3JlYXRpb24gc3RyYXRlZ3kgd2FzIGludmFsaWQ6JywgdGhpcy5vcHRpb25zLnN0cmF0ZWd5KTtcbiAgICB9XG5cbiAgICB0aGlzLnN0cmF0ZWd5ID0gbmV3IFN0cmF0ZWd5Q3Rvcih0aGlzLnJ1biwgdGhpcy5vcHRpb25zKTtcbn1cblxuUnVuTWFuYWdlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSAnZ29vZCcgcnVuLlxuICAgICAqXG4gICAgICogQSBnb29kIHJ1biBpcyBkZWZpbmVkIGJ5IHRoZSBzdHJhdGVneS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBzdHJhdGVneSBpcyBgYWx3YXlzLW5ld2AsIHRoZSBjYWxsXG4gICAgICogdG8gYGdldFJ1bigpYCBhbHdheXMgcmV0dXJucyBhIG5ld2x5IGNyZWF0ZWQgcnVuOyBpZiB0aGUgc3RyYXRlZ3kgaXMgYG5ldy1pZi1wZXJzaXN0ZWRgLFxuICAgICAqIGBnZXRSdW4oKWAgY3JlYXRlcyBhIG5ldyBydW4gaWYgdGhlIHByZXZpb3VzIHJ1biBpcyBpbiBhIHBlcnNpc3RlZCBzdGF0ZSwgb3RoZXJ3aXNlXG4gICAgICogaXQgcmV0dXJucyB0aGUgcHJldmlvdXMgcnVuLiBTZWUgW1J1biBNYW5hZ2VyIFN0cmF0ZWdpZXNdKC4uLy4uL3N0cmF0ZWd5LykgZm9yIG1vcmUgb24gc3RyYXRlZ2llcy5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5nZXRSdW4oKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqIEByZXR1cm4geyRwcm9taXNlfSBQcm9taXNlIHRvIGNvbXBsZXRlIHRoZSBjYWxsLlxuICAgICAqL1xuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdHJhdGVneVxuICAgICAgICAgICAgICAgIC5nZXRSdW4oKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSBuZXcgcnVuLCByZWdhcmRsZXNzIG9mIHN0cmF0ZWd5OiBmb3JjZSBjcmVhdGlvbiBvZiBhIG5ldyBydW4uXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgcm0ucmVzZXQoKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIChuZXcpIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBydW5TZXJ2aWNlT3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgUnVuIFNlcnZpY2UuIFNlZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBmb3IgbW9yZS5cbiAgICAgKi9cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5LnJlc2V0KHJ1blNlcnZpY2VPcHRpb25zKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJ1bk1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIC8vIGFsd2F5cyBjcmVhdGUgYSBuZXcgcnVuIVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1ha2VTZXEgPSByZXF1aXJlKCcuLi8uLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFNlc3Npb25TdG9yZSA9IHJlcXVpcmUoJy4uLy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBVcmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgc2Vzc2lvblN0b3JlID0gbmV3IFNlc3Npb25TdG9yZSh7fSk7XG52YXIgdXJsU2VydmljZSA9IG5ldyBVcmxTZXJ2aWNlKCk7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9rZXktbmFtZXMnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHNlc3Npb25LZXk6IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZLFxuICAgIHBhdGg6ICcnXG59O1xuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBwYXRoKSB7XG4gICAgaWYgKCFwYXRoKSB7XG4gICAgICAgIGlmICghdXJsU2VydmljZS5pc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgICAgICBwYXRoID0gJy8nICsgW3VybFNlcnZpY2UuYXBwUGF0aCwgdXJsU2VydmljZS5hY2NvdW50UGF0aCwgdXJsU2VydmljZS5wcm9qZWN0UGF0aF0uam9pbignLycpO1xuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHdlIGRvbid0IGdldCBjb25zZWN1dGVpdmUgJy8nIHNvIHdlIGhhdmUgYSB2YWxpZCBwYXRoIGZvciB0aGUgc2Vzc2lvblxuICAgICAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZSgvXFwvezIsfS9nLCcvJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYXRoID0gJyc7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gc2V0IHRoZSBzZWVzaW9uS2V5IGZvciB0aGUgcnVuXG4gICAgc2Vzc2lvblN0b3JlLnNldChzZXNzaW9uS2V5LCBKU09OLnN0cmluZ2lmeSh7IHJ1bklkOiBydW4uaWQgfSksIHsgcm9vdDogcGF0aCB9KTtcbn1cblxuLyoqXG4qIENvbmRpdGlvbmFsIENyZWF0aW9uIFN0cmF0ZWd5XG4qIFRoaXMgc3RyYXRlZ3kgd2lsbCB0cnkgdG8gZ2V0IHRoZSBydW4gc3RvcmVkIGluIHRoZSBjb29raWUgYW5kXG4qIGV2YWx1YXRlIGlmIG5lZWRzIHRvIGNyZWF0ZSBhIG5ldyBydW4gYnkgY2FsbGluZyB0aGUgJ2NvbmRpdGlvbicgZnVuY3Rpb25cbiovXG5cbi8qIGpzaGludCBlcW51bGw6IHRydWUgKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KHJ1blNlcnZpY2UsIGNvbmRpdGlvbiwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChjb25kaXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb25kaXRpb25hbCBzdHJhdGVneSBuZWVkcyBhIGNvbmRpdGlvbiB0byBjcmVhdGV0ZSBhIHJ1bicpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fYXV0aCA9IG5ldyBBdXRoTWFuYWdlcigpO1xuICAgICAgICB0aGlzLnJ1biA9IG1ha2VTZXEocnVuU2VydmljZSk7XG4gICAgICAgIHRoaXMuY29uZGl0aW9uID0gdHlwZW9mIGNvbmRpdGlvbiAhPT0gJ2Z1bmN0aW9uJyA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNvbmRpdGlvbjsgfSA6IGNvbmRpdGlvbjtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9LFxuXG4gICAgcnVuT3B0aW9uc1dpdGhTY29wZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdXNlclNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiB1c2VyU2Vzc2lvbi5ncm91cE5hbWUgfVxuICAgICAgICB9LCB0aGlzLnJ1bk9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBvcHQgPSB0aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5ydW5cbiAgICAgICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgc2V0UnVuSW5TZXNzaW9uKF90aGlzLm9wdGlvbnMuc2Vzc2lvbktleSwgcnVuLCBfdGhpcy5vcHRpb25zLnBhdGgpO1xuICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmUuZ2V0KHRoaXMub3B0aW9ucy5zZXNzaW9uS2V5KSk7XG5cbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRBbmRDaGVjayhydW5TZXNzaW9uKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgX2xvYWRBbmRDaGVjazogZnVuY3Rpb24gKHJ1blNlc3Npb24pIHtcbiAgICAgICAgdmFyIHNob3VsZENyZWF0ZSA9IGZhbHNlO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1blxuICAgICAgICAgICAgLmxvYWQocnVuU2Vzc2lvbi5ydW5JZCwgbnVsbCwge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uIChydW4sIG1zZywgaGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBzaG91bGRDcmVhdGUgPSBfdGhpcy5jb25kaXRpb24uY2FsbChfdGhpcywgcnVuLCBoZWFkZXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIGlmIChzaG91bGRDcmVhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9wdCA9IF90aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgbmVlZCB0byBkbyB0aGlzLCBvbiB0aGUgb3JpZ2luYWwgcnVuU2VydmljZSAoaWUgbm90IHNlcXVlbmNpYWxpemVkKVxuICAgICAgICAgICAgICAgICAgICAvLyBzbyB3ZSBkb24ndCBnZXQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1bi5vcmlnaW5hbC5jcmVhdGUob3B0KVxuICAgICAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oX3RoaXMub3B0aW9ucy5zZXNzaW9uS2V5LCBydW4pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnN0YXJ0KCk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSAgPSBydW5TZXJ2aWNlO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSBuZXdseSBjcmVhdGVkIHJ1blxuICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoKS5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSh0aGlzLnJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vaWRlbnRpdHktc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0b3JlOiB7XG4gICAgICAgIHN5bmNocm9ub3VzOiB0cnVlXG4gICAgfVxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcblxuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMud29ybGRBcGkgPSBuZXcgV29ybGRBcGlBZGFwdGVyKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciB3b3JsZEFwaSA9IHRoaXMud29ybGRBcGk7XG4gICAgICAgIHZhciBtb2RlbCA9IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAoIWN1clVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDAsIGVycm9yOiAnV2UgbmVlZCBhbiBhdXRoZW50aWNhdGVkIHVzZXIgdG8gam9pbiBhIG11bHRpcGxheWVyIHdvcmxkLiAoRVJSOiBubyB1c2VySWQgaW4gc2Vzc2lvbiknIH0sIHNlc3Npb24pLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsb2FkUnVuRnJvbVdvcmxkID0gZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDQsIGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IGluIGFueSB3b3JsZC4nIH0sIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oX3RoaXMuX2xvYWRSdW4pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgZHRkLnJlamVjdChlcnJvciwgc2Vzc2lvbiwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIF9sb2FkUnVuOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIFN0YXRlQXBpID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICAgICAgdGhpcy5fc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICAgICAgdGhpcy5zdGF0ZUFwaSA9IG5ldyBTdGF0ZUFwaSgpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZEFuZENoZWNrID0gdGhpcy5fbG9hZEFuZENoZWNrLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVSdW4gPSB0aGlzLl9yZXN0b3JlUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2dldEFsbFJ1bnMgPSB0aGlzLl9nZXRBbGxSdW5zLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0QWxsUnVucygpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9sb2FkQW5kQ2hlY2spO1xuICAgIH0sXG5cbiAgICBfZ2V0QWxsUnVuczogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2UodGhpcy5fc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9Jyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5xdWVyeSh7XG4gICAgICAgICAgICAndXNlci5pZCc6IHNlc3Npb24udXNlcklkIHx8ICcwMDAwJyxcbiAgICAgICAgICAgICdzY29wZS5ncm91cCc6IHNlc3Npb24uZ3JvdXBOYW1lXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVucykge1xuICAgICAgICBpZiAoIXJ1bnMgfHwgIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGVDb21wID0gZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIuZGF0ZSkgLSBuZXcgRGF0ZShhLmRhdGUpOyB9O1xuICAgICAgICB2YXIgbGF0ZXN0UnVuID0gcnVucy5zb3J0KGRhdGVDb21wKVswXTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHNob3VsZFJlcGxheSA9IGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGxhdGVzdFJ1bi5pZCwgbnVsbCwge1xuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVwbGF5ID0gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2hvdWxkUmVwbGF5ID8gX3RoaXMuX3Jlc3RvcmVSdW4ocnVuLmlkKSA6IHJ1bjtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9yZXN0b3JlUnVuOiBmdW5jdGlvbiAocnVuSWQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVBcGkucmVwbGF5KHsgcnVuSWQ6IHJ1bklkIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJ1bihyZXNwLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW4ubG9hZChpZCwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgICduZXctaWYtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLFxuICAgICduZXctaWYtcGVyc2lzdGVkJzogcmVxdWlyZSgnLi9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1taXNzaW5nJzogcmVxdWlyZSgnLi9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpLFxuICAgICdhbHdheXMtbmV3JzogcmVxdWlyZSgnLi9hbHdheXMtbmV3LXN0cmF0ZWd5JyksXG4gICAgJ211bHRpcGxheWVyJzogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdwZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXInOiByZXF1aXJlKCcuL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneScpLFxuICAgICdub25lJzogcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgdmFsaWRGaWx0ZXI6IHsgc2F2ZWQ6IHRydWUgfVxufTtcblxuZnVuY3Rpb24gU2NlbmFyaW9NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMucnVuU2VydmljZSA9IHRoaXMub3B0aW9ucy5ydW4gfHwgbmV3IFJ1blNlcnZpY2UodGhpcy5vcHRpb25zKTtcbn1cblxuU2NlbmFyaW9NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy52YWxpZEZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlcik7XG4gICAgfSxcblxuICAgIGxvYWRWYXJpYWJsZXM6IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UucXVlcnkodGhpcy5maWx0ZXIsIHsgaW5jbHVkZTogdmFycyB9KTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgbWV0YSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2VydmljZShydW4pLnNhdmUoJC5leHRlbmQodHJ1ZSwge30sIHsgc2F2ZWQ6IHRydWUgfSwgbWV0YSkpO1xuICAgIH0sXG5cbiAgICBhcmNoaXZlOiBmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSh7IHNhdmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuXG4gICAgX2dldFNlcnZpY2U6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW4gfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdvYmplY3QnICYmIHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NhdmUgbWV0aG9kIHJlcXVpcmVzIGEgcnVuIHNlcnZpY2Ugb3IgYSBydW5JZCcpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW5JZCB9KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICByZXNldDogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucywgbWFuYWdlcikge1xuICAgICAgICByZXR1cm4gbWFuYWdlci5yZXNldChvcHRpb25zKTtcbiAgICB9XG59O1xuIiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9ICByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG4vLyB2YXIgZGVmYXVsdHMgPSB7XG4vLyAgYWNjb3VudDogJycsXG4vLyAgcHJvamVjdDogJycsXG4vLyAgZ3JvdXA6ICcnLFxuLy8gIHRyYW5zcG9ydDoge1xuLy8gIH1cbi8vIH07XG5cblxuZnVuY3Rpb24gYnVpbGRTdHJhdGVneSh3b3JsZElkLCBkdGQpIHtcblxuICAgIHJldHVybiBmdW5jdGlvbiBDdG9yKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICAkLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm90IGltcGxlbWVudGQuIE5lZWQgYXBpIGNoYW5nZXMnKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlLmNhbGwodGhpcywgcnVuLCBfdGhpcy5ydW5TZXJ2aWNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcklkYCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSBncm91cCBmb3IgdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bih7bW9kZWw6ICdteU1vZGVsLnB5J30pXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBtb2RlbGAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgbW9kZWwgZmlsZS4gUmVxdWlyZWQgaWYgbm90IGFscmVhZHkgcGFzc2VkIGluIGFzIGBydW4ubW9kZWxgIHdoZW4gdGhlIFdvcmxkIE1hbmFnZXIgaXMgY3JlYXRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgX3RoaXMub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJtLmdldFJ1bigpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHJ1biwgcm0ucnVuU2VydmljZSwgcm0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5nZXRDdXJyZW50V29ybGQoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bik7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIGFwaSk7XG59O1xuIiwiLyoqXG4gKiAjI0ZpbGUgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGlzIGlzIHVzZWQgdG8gdXBsb2FkL2Rvd25sb2FkIGZpbGVzIGRpcmVjdGx5IG9udG8gRXBpY2VudGVyLCBhbmFsb2dvdXMgdG8gdXNpbmcgdGhlIEZpbGUgTWFuYWdlciBVSSBpbiBFcGljZW50ZXIgZGlyZWN0bHkgb3IgU0ZUUGluZyBmaWxlcyBpbi4gVGhlIEFzc2V0IEFQSSBpcyB0eXBpY2FsbHkgdXNlZCBmb3IgYWxsIHByb2plY3QgdXNlLWNhc2VzLCBhbmQgaXQncyB1bmxpa2VseSB0aGlzIEZpbGUgU2VydmljZSB3aWxsIGJlIHVzZWQgZGlyZWN0bHkgZXhjZXB0IGJ5IEFkbWluIHRvb2xzIChlLmcuIEZsb3cgSW5zcGVjdG9yKS5cbiAqXG4gKiBQYXJ0aWFsbHkgaW1wbGVtZW50ZWQuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCBzdG9yZS5nZXQoJ2VwaWNlbnRlci50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZmlsZScpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQXN5bmNBUEkgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgYSBkaXJlY3RvcnkgbGlzdGluZywgb3IgY29udGVudHMgb2YgYSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGZpbGVQYXRoYCAgIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZm9sZGVyVHlwZWAgT25lIG9mIE1vZGVsfFN0YXRpY3xOb2RlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBnZXRDb250ZW50czogZnVuY3Rpb24gKGZpbGVQYXRoLCBmb2xkZXJUeXBlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IGZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbi8vIHZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGtleU5hbWVzID0gcmVxdWlyZSgnLi4vbWFuYWdlcnMva2V5LW5hbWVzJyk7XG5cbnZhciBhcGlFbmRwb2ludCA9ICdhc3NldCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZShzdG9yZS5nZXQoa2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZKSB8fCAne30nKTtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9DT09LSUVfS0VZKSB8fCAnJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gRGVmYXVsdHMgdG8gc2Vzc2lvbidzIGBncm91cE5hbWVgLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogc2Vzc2lvbi51c2VySWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgc2NvcGUgZm9yIHRoZSBhc3NldC4gVmFsaWQgdmFsdWVzIGFyZTogYHVzZXJgLCBgZ3JvdXBgLCBhbmQgYHByb2plY3RgLiBTZWUgYWJvdmUgZm9yIHRoZSByZXF1aXJlZCBwZXJtaXNzaW9ucyB0byB3cml0ZSB0byBlYWNoIHNjb3BlLiBEZWZhdWx0cyB0byBgdXNlcmAsIG1lYW5pbmcgdGhlIGN1cnJlbnQgZW5kIHVzZXIgb3IgYSBmYWNpbGl0YXRvciBpbiB0aGUgZW5kIHVzZXIncyBncm91cCBjYW4gZWRpdCB0aGUgYXNzZXQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBzY29wZTogJ3VzZXInLFxuICAgICAgICAvKipcbiAgICAgICAgICogRGV0ZXJtaW5lcyBpZiBhIHJlcXVlc3QgdG8gbGlzdCB0aGUgYXNzZXRzIGluIGEgc2NvcGUgaW5jbHVkZXMgdGhlIGNvbXBsZXRlIFVSTCBmb3IgZWFjaCBhc3NldCAoYHRydWVgKSwgb3Igb25seSB0aGUgZmlsZSBuYW1lcyBvZiB0aGUgYXNzZXRzIChgZmFsc2VgKS4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGZ1bGxVcmw6IHRydWUsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgdHJhbnNwb3J0IG9iamVjdCBjb250YWlucyB0aGUgb3B0aW9ucyBwYXNzZWQgdG8gdGhlIFhIUiByZXF1ZXN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7XG4gICAgICAgICAgICBwcm9jZXNzRGF0YTogZmFsc2VcbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIGFzc2V0QXBpUGFyYW1zID0gWydlbmNvZGluZycsICdkYXRhJywgJ2NvbnRlbnRUeXBlJ107XG4gICAgdmFyIHNjb3BlQ29uZmlnID0ge1xuICAgICAgICB1c2VyOiBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSxcbiAgICAgICAgZ3JvdXA6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10sXG4gICAgICAgIHByb2plY3Q6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0J10sXG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZUZpbGVuYW1lID0gZnVuY3Rpb24gKGZpbGVuYW1lKSB7XG4gICAgICAgIGlmICghZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZmlsZW5hbWUgaXMgbmVlZGVkLicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZVVybFBhcmFtcyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICBpZiAoIXBhcnRLZXlzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Njb3BlIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cblxuICAgICAgICAkLmVhY2gocGFydEtleXMsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICghb3B0aW9uc1t0aGlzXSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzICsgJyBwYXJhbWV0ZXIgaXMgbmVlZGVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgdmFyIGJ1aWxkVXJsID0gZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgIHZhbGlkYXRlVXJsUGFyYW1zKG9wdGlvbnMpO1xuICAgICAgICB2YXIgcGFydEtleXMgPSBzY29wZUNvbmZpZ1tvcHRpb25zLnNjb3BlXTtcbiAgICAgICAgdmFyIHBhcnRzID0gJC5tYXAocGFydEtleXMsIGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zW2tleV07XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgcHJldmVudHMgYWRkaW5nIGEgdHJhaWxpbmcgLyBpbiB0aGUgVVJMIGFzIHRoZSBBc3NldCBBUElcbiAgICAgICAgICAgIC8vIGRvZXMgbm90IHdvcmsgY29ycmVjdGx5IHdpdGggaXRcbiAgICAgICAgICAgIGZpbGVuYW1lID0gJy8nICsgZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHBhcnRzLmpvaW4oJy8nKSArIGZpbGVuYW1lO1xuICAgIH07XG5cbiAgICAvLyBQcml2YXRlIGZ1bmN0aW9uLCBhbGwgcmVxdWVzdHMgZm9sbG93IGEgbW9yZSBvciBsZXNzIHNhbWUgYXBwcm9hY2ggdG9cbiAgICAvLyB1c2UgdGhlIEFzc2V0IEFQSSBhbmQgdGhlIGRpZmZlcmVuY2UgaXMgdGhlIEhUVFAgdmVyYlxuICAgIC8vXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBtZXRob2RgIChSZXF1aXJlZCkgSFRUUCB2ZXJiXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS9yZXBsYWNlL2NyZWF0ZVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUElcbiAgICAvLyBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgdmFyIHVwbG9hZCA9IGZ1bmN0aW9uIChtZXRob2QsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVGaWxlbmFtZShmaWxlbmFtZSk7XG4gICAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgcGFyYW1ldGVyIGlzIGNsZWFuXG4gICAgICAgIG1ldGhvZCA9IG1ldGhvZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB2YXIgY29udGVudFR5cGUgPSBwYXJhbXMgaW5zdGFuY2VvZiBGb3JtRGF0YSA9PT0gdHJ1ZSA/IGZhbHNlIDogJ2FwcGxpY2F0aW9uL2pzb24nO1xuICAgICAgICBpZiAoY29udGVudFR5cGUgPT09ICdhcHBsaWNhdGlvbi9qc29uJykge1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIGFzc2V0QXBpUGFyYW1zKTtcbiAgICAgICAgfSBlbHNlIHsgLy8gZWxzZSB3ZSdyZSBzZW5kaW5nIGZvcm0gZGF0YSB3aGljaCBnb2VzIGRpcmVjdGx5IGluIHJlcXVlc3QgYm9keVxuICAgICAgICAgICAgLy8gRm9yIG11bHRpcGFydC9mb3JtLWRhdGEgdXBsb2FkcyB0aGUgZmlsZW5hbWUgaXMgbm90IHNldCBpbiB0aGUgVVJMLFxuICAgICAgICAgICAgLy8gaXQncyBnZXR0aW5nIHBpY2tlZCBieSB0aGUgRm9ybURhdGEgZmllbGQgZmlsZW5hbWUuXG4gICAgICAgICAgICBmaWxlbmFtZSA9IG1ldGhvZCA9PT0gJ3Bvc3QnIHx8IG1ldGhvZCA9PT0gJ3B1dCcgPyAnJyA6IGZpbGVuYW1lO1xuICAgICAgICB9XG4gICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCwgY29udGVudFR5cGU6IGNvbnRlbnRUeXBlIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwW21ldGhvZF0ocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS4gVGhlIHNlcnZlciByZXR1cm5zIGFuIGVycm9yIChzdGF0dXMgY29kZSBgNDA5YCwgY29uZmxpY3QpIGlmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLCBzb1xuICAgICAgICAqIGNoZWNrIGZpcnN0IHdpdGggYSBgbGlzdCgpYCBvciBhIGBnZXQoKWAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBhYSA9IG5ldyBGLnNlcnZpY2UuQXNzZXQoe1xuICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAgICAqICAgICAgICAgIHVzZXJJZDogJydcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAgICAgICAgKiAgICAgICBhYS5jcmVhdGUoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gICAgICAgICogICAgICAgICAgIGNvbnRlbnRUeXBlOiAndGV4dC9wbGFpbidcbiAgICAgICAgKiAgICAgICB9LCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyBhbHRlcm5hdGl2ZWx5LCBjcmVhdGUgYSBuZXcgYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJ1cGxvYWQtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5VcGxvYWQgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3VwbG9hZC1maWxlJykub24oJ3N1Ym1pdCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLmNyZWF0ZShmaWxlbmFtZSwgZGF0YSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gY3JlYXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUEkuIFJlcXVpcmVkIGlmIHRoZSBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYCwgb3RoZXJ3aXNlIGlnbm9yZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZW5jb2RpbmdgIEVpdGhlciBgSEVYYCBvciBgQkFTRV82NGAuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmRhdGFgIFRoZSBlbmNvZGVkIGRhdGEgZm9yIHRoZSBmaWxlLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5jb250ZW50VHlwZWAgVGhlIG1pbWUgdHlwZSBvZiB0aGUgZmlsZS4gT3B0aW9uYWwuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3Bvc3QnLCBmaWxlbmFtZSwgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGEgZmlsZSBmcm9tIHRoZSBBc3NldCBBUEksIGZldGNoaW5nIHRoZSBhc3NldCBjb250ZW50LiAoVG8gZ2V0IGEgbGlzdFxuICAgICAgICAqIG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZSwgdXNlIGBsaXN0KClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byByZXRyaWV2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBnZXRTZXJ2aWNlT3B0aW9ucyA9IF9waWNrKHNlcnZpY2VPcHRpb25zLCBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSk7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBnZXRTZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBsaXN0IG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5saXN0KHsgZnVsbFVybDogdHJ1ZSB9KS50aGVuKGZ1bmN0aW9uKGZpbGVMaXN0KXtcbiAgICAgICAgKiAgICAgICAgICAgY29uc29sZS5sb2coJ2FycmF5IG9mIGZpbGVzID0gJywgZmlsZUxpc3QpO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5zY29wZWAgKE9wdGlvbmFsKSBUaGUgc2NvcGUgKGB1c2VyYCwgYGdyb3VwYCwgYHByb2plY3RgKS5cbiAgICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGBvcHRpb25zLmZ1bGxVcmxgIChPcHRpb25hbCkgRGV0ZXJtaW5lcyBpZiB0aGUgbGlzdCBvZiBhc3NldHMgaW4gYSBzY29wZSBpbmNsdWRlcyB0aGUgY29tcGxldGUgVVJMIGZvciBlYWNoIGFzc2V0IChgdHJ1ZWApLCBvciBvbmx5IHRoZSBmaWxlIG5hbWVzIG9mIHRoZSBhc3NldHMgKGBmYWxzZWApLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybCgnJywgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuICAgICAgICAgICAgdmFyIGZ1bGxVcmwgPSBnZXRPcHRpb25zLmZ1bGxVcmw7XG5cbiAgICAgICAgICAgIGlmICghZnVsbFVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZnVsbFBhdGhGaWxlcyA9ICQubWFwKGZpbGVzLCBmdW5jdGlvbiAoZmlsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoZnVsbFBhdGhGaWxlcywgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlcGxhY2VzIGFuIGV4aXN0aW5nIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyByZXBsYWNlIGFuIGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLnJlcGxhY2UoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhObFkyOXVaQ0IwWlhOMElHWnBiR1V1JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJyZXBsYWNlLWZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwicmVwbGFjZS1maWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5SZXBsYWNlIG15RmlsZTwvYnV0dG9uPlxuICAgICAgICAqICAgICAgIC8vIDwvZm9ybT5cbiAgICAgICAgKiAgICAgICAvL1xuICAgICAgICAqICAgICAgICQoJyNyZXBsYWNlLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI3JlcGxhY2UtZmlsZW5hbWUnKS52YWwoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICAgICAgICAqICAgICAgICAgIGRhdGEuYXBwZW5kKCdmaWxlJywgaW5wdXRDb250cm9sLmZpbGVzWzBdLCBmaWxlbmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICBhYS5yZXBsYWNlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgYmVpbmcgcmVwbGFjZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgcmVwbGFjZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3B1dCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5kZWxldGUoc2FtcGxlRmlsZU5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ2RlbGV0ZScsIGZpbGVuYW1lLCB7fSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYXNzZXRVcmw6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlIHByb3ZpZGVzIG1ldGhvZHMgZm9yIGxvZ2dpbmcgaW4gYW5kIGxvZ2dpbmcgb3V0LiBPbiBsb2dpbiwgdGhpcyBzZXJ2aWNlIGNyZWF0ZXMgYW5kIHJldHVybnMgYSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAqXG4gKiBVc2VyIGFjY2VzcyB0b2tlbnMgYXJlIHJlcXVpcmVkIGZvciBlYWNoIGNhbGwgdG8gRXBpY2VudGVyLiAoU2VlIFtQcm9qZWN0IEFjY2Vzc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4pXG4gKlxuICogSWYgeW91IG5lZWQgYWRkaXRpb25hbCBmdW5jdGlvbmFsaXR5IC0tIHN1Y2ggYXMgdHJhY2tpbmcgc2Vzc2lvbiBpbmZvcm1hdGlvbiwgZWFzaWx5IHJldHJpZXZpbmcgdGhlIHVzZXIgdG9rZW4sIG9yIGdldHRpbmcgdGhlIGdyb3VwcyB0byB3aGljaCBhbiBlbmQgdXNlciBiZWxvbmdzIC0tIGNvbnNpZGVyIHVzaW5nIHRoZSBbQXV0aG9yaXphdGlvbiBNYW5hZ2VyXSguLi9hdXRoLW1hbmFnZXIvKSBpbnN0ZWFkLlxuICpcbiAqICAgICAgdmFyIGF1dGggPSBuZXcgRi5zZXJ2aWNlLkF1dGgoKTtcbiAqICAgICAgYXV0aC5sb2dpbih7IHVzZXJOYW1lOiAnanNtaXRoQGFjbWVzaW11bGF0aW9ucy5jb20nLFxuICogICAgICAgICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyB9KTtcbiAqICAgICAgYXV0aC5sb2dvdXQoKTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VyTmFtZTogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFzc3dvcmQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gUmVxdWlyZWQgaWYgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdhdXRoZW50aWNhdGlvbicpXG4gICAgfSk7XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvZ3MgdXNlciBpbiwgcmV0dXJuaW5nIHRoZSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAgICAgICAgICpcbiAgICAgICAgICogSWYgbm8gYHVzZXJOYW1lYCBvciBgcGFzc3dvcmRgIHdlcmUgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLCB0aGV5IGFyZSByZXF1aXJlZCBpbiB0aGUgYG9wdGlvbnNgIGhlcmUuIElmIG5vIGBhY2NvdW50YCB3YXMgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zIGFuZCB0aGUgYHVzZXJOYW1lYCBpcyBmb3IgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGUgYGFjY291bnRgIGlzIHJlcXVpcmVkIGFzIHdlbGwuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgYXV0aC5sb2dpbih7XG4gICAgICAgICAqICAgICAgICAgIHVzZXJOYW1lOiAnanNtaXRoJyxcbiAgICAgICAgICogICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcsXG4gICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyB9KVxuICAgICAgICAgKiAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhcInVzZXIgYWNjZXNzIHRva2VuIGlzOiBcIiwgdG9rZW4uYWNjZXNzX3Rva2VuKTtcbiAgICAgICAgICogICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHN1Y2Nlc3M6ICQubm9vcCB9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBpZiAoIWh0dHBPcHRpb25zLnVzZXJOYW1lIHx8ICFodHRwT3B0aW9ucy5wYXNzd29yZCkge1xuICAgICAgICAgICAgICAgIHZhciByZXNwID0geyBzdGF0dXM6IDQwMSwgc3RhdHVzTWVzc2FnZTogJ05vIHVzZXJuYW1lIG9yIHBhc3N3b3JkIHNwZWNpZmllZC4nIH07XG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvci5jYWxsKHRoaXMsIHJlc3ApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVqZWN0KHJlc3ApLnByb21pc2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHBvc3RQYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgdXNlck5hbWU6IGh0dHBPcHRpb25zLnVzZXJOYW1lLFxuICAgICAgICAgICAgICAgIHBhc3N3b3JkOiBodHRwT3B0aW9ucy5wYXNzd29yZCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoaHR0cE9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vcGFzcyBpbiBudWxsIGZvciBhY2NvdW50IHVuZGVyIG9wdGlvbnMgaWYgeW91IGRvbid0IHdhbnQgaXQgdG8gYmUgc2VudFxuICAgICAgICAgICAgICAgIHBvc3RQYXJhbXMuYWNjb3VudCA9IGh0dHBPcHRpb25zLmFjY291bnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocG9zdFBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2dzIHVzZXIgb3V0IGZyb20gc3BlY2lmaWVkIGFjY291bnRzLlxuICAgICAgICAgKiBFcGljZW50ZXIgbG9nb3V0IGlzIG5vdCBpbXBsZW1lbnRlZCB5ZXQsIGFkZGVkIGEgZHVtbXkgcHJvbWlzZSB0aGF0IGdldHMgYXV0b21hdGljYWxseSByZXNvbHZlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBhdXRoLmxvZ291dCgpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2dvdXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgZHRkLnJlc29sdmUoKTtcbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqICMjIENoYW5uZWwgU2VydmljZVxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBDaGFubmVsIFNlcnZpY2UgaXMgYSBidWlsZGluZyBibG9jayBmb3IgdGhpcyBmdW5jdGlvbmFsaXR5LiBJdCBjcmVhdGVzIGEgcHVibGlzaC1zdWJzY3JpYmUgb2JqZWN0LCBhbGxvd2luZyB5b3UgdG8gcHVibGlzaCBtZXNzYWdlcywgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzLCBvciB1bnN1YnNjcmliZSBmcm9tIG1lc3NhZ2VzIGZvciBhIGdpdmVuICd0b3BpYycgb24gYSBgJC5jb21ldGRgIHRyYW5zcG9ydCBpbnN0YW5jZS5cbiAqXG4gKiBUeXBpY2FsbHksIHlvdSB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgdG8gY3JlYXRlIG9yIHJldHJpZXZlIGNoYW5uZWxzLCB0aGVuIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gbGlzdGVuIHRvIG9yIHVwZGF0ZSBkYXRhLiAoRm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZCBvbiBFcGljZW50ZXIncyBwdXNoIGNoYW5uZWwsIHNlZSB0aGUgaW50cm9kdWN0b3J5IG5vdGVzIG9uIHRoZSBbUHVzaCBDaGFubmVsIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvKSBwYWdlLilcbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UuIFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLlxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCwgdGhlbiBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbiAqXG4gKiAgICAgICAgdmFyIGNzID0gbmV3IEYuc2VydmljZS5DaGFubmVsKCk7XG4gKiAgICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgU2VydmljZSBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgU2VydmljZS5cbiAqICogYG9wdGlvbnMuYmFzZWAgVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLnRvcGljUmVzb2x2ZXJgIEEgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgYWxsICd0b3BpY3MnIHBhc3NlZCBpbnRvIHRoZSBgcHVibGlzaGAgYW5kIGBzdWJzY3JpYmVgIG1ldGhvZHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGltcGxlbWVudCB5b3VyIG93biBzZXJpYWxpemUgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGN1c3RvbSBvYmplY3RzIHRvIHRvcGljIG5hbWVzLiBSZXR1cm5zIGEgU3RyaW5nLiBCeSBkZWZhdWx0LCBpdCBqdXN0IGVjaG9lcyB0aGUgdG9waWMuXG4gKiAqIGBvcHRpb25zLnRyYW5zcG9ydGAgVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLiBTZWUgaHR0cDovL2RvY3MuY29tZXRkLm9yZy9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gY29tZXRkLlxuICovXG52YXIgQ2hhbm5lbCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYmFzZSB0b3BpYy4gVGhpcyBpcyBhZGRlZCBhcyBhIHByZWZpeCB0byBhbGwgZnVydGhlciB0b3BpY3MgeW91IHB1Ymxpc2ggb3Igc3Vic2NyaWJlIHRvIHdoaWxlIHdvcmtpbmcgd2l0aCB0aGlzIENoYW5uZWwgU2VydmljZS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGJhc2U6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqIGB0b3BpY2AgVG9waWMgdG8gcGFyc2UuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiAqU3RyaW5nKjogVGhpcyBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIGEgc3RyaW5nIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICB0b3BpY1Jlc29sdmVyOiBmdW5jdGlvbiAodG9waWMpIHtcbiAgICAgICAgICAgIHJldHVybiB0b3BpYztcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiBudWxsXG4gICAgfTtcbiAgICB0aGlzLmNoYW5uZWxPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbn07XG5cbnZhciBtYWtlTmFtZSA9IGZ1bmN0aW9uIChjaGFubmVsTmFtZSwgdG9waWMpIHtcbiAgICAvL1JlcGxhY2UgdHJhaWxpbmcvZG91YmxlIHNsYXNoZXNcbiAgICB2YXIgbmV3TmFtZSA9IChjaGFubmVsTmFtZSA/IChjaGFubmVsTmFtZSArICcvJyArIHRvcGljKSA6IHRvcGljKS5yZXBsYWNlKC9cXC9cXC8vZywgJy8nKS5yZXBsYWNlKC9cXC8kLywnJyk7XG4gICAgcmV0dXJuIG5ld05hbWU7XG59O1xuXG5cbkNoYW5uZWwucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbC5wcm90b3R5cGUsIHtcblxuICAgIC8vIGZ1dHVyZSBmdW5jdGlvbmFsaXR5OlxuICAgIC8vICAgICAgLy8gU2V0IHRoZSBjb250ZXh0IGZvciB0aGUgY2FsbGJhY2tcbiAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgZnVuY3Rpb24gKCkgeyB0aGlzLmlubmVySFRNTCA9ICdUcmlnZ2VyZWQnfSwgZG9jdW1lbnQuYm9keSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gQ29udHJvbCB0aGUgb3JkZXIgb2Ygb3BlcmF0aW9ucyBieSBzZXR0aW5nIHRoZSBgcHJpb3JpdHlgXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4nLCBjYiwgdGhpcywge3ByaW9yaXR5OiA5fSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIDUwXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiA1MH0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBncmVhdGVyIHRoYW4gNTBcbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6ICc+NTAnfSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIGV2ZW5cbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6IGZ1bmN0aW9uICh2YWwpIHtyZXR1cm4gdmFsICUgMiA9PT0gMH19KTtcblxuXG4gICAgLyoqXG4gICAgICogU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqIFRoZSB0b3BpYyBzaG91bGQgaW5jbHVkZSB0aGUgZnVsbCBwYXRoIG9mIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cyksIHByb2plY3QgaWQsIGFuZCBncm91cCBuYW1lLiAoSW4gbW9zdCBjYXNlcywgaXQgaXMgc2ltcGxlciB0byB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgaW5zdGVhZCwgaW4gd2hpY2ggY2FzZSB0aGlzIGlzIGNvbmZpZ3VyZWQgZm9yIHlvdS4pXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlcyoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjYiA9IGZ1bmN0aW9uKHZhbCkgeyBjb25zb2xlLmxvZyh2YWwuZGF0YSk7IH07XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9wLWxldmVsICdydW4nIHRvcGljXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGNoaWxkcmVuIG9mIHRoZSAncnVuJyB0b3BpYy4gTm90ZSB0aGlzIHdpbGwgYWxzbyBiZSB0cmlnZ2VyZWQgZm9yIGNoYW5nZXMgdG8gcnVuLngueS56LlxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuLyonLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGJvdGggdGhlIHRvcC1sZXZlbCAncnVuJyB0b3BpYyBhbmQgaXRzIGNoaWxkcmVuXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoWycvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJyxcbiAgICAgKiAgICAgICAgICAnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJ10sIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSBwYXJ0aWN1bGFyIHZhcmlhYmxlXG4gICAgICogICAgICBzdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzL3ByaWNlJywgY2IpO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpTdHJpbmcqIFJldHVybnMgYSB0b2tlbiB5b3UgY2FuIGxhdGVyIHVzZSB0byB1bnN1YnNjcmliZS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfEFycmF5fSAgIGB0b3BpY2AgICAgTGlzdCBvZiB0b3BpY3MgdG8gbGlzdGVuIGZvciBjaGFuZ2VzIG9uLlxuICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBgY2FsbGJhY2tgIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGV4ZWN1dGUuIENhbGxiYWNrIGlzIGNhbGxlZCB3aXRoIHNpZ25hdHVyZSBgKGV2dCwgcGF5bG9hZCwgbWV0YWRhdGEpYC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgYGNvbnRleHRgICBDb250ZXh0IGluIHdoaWNoIHRoZSBgY2FsbGJhY2tgIGlzIGV4ZWN1dGVkLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gICBgb3B0aW9uc2AgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICogQHBhcmFtICB7TnVtYmVyfSAgIGBvcHRpb25zLnByaW9yaXR5YCAgVXNlZCB0byBjb250cm9sIG9yZGVyIG9mIG9wZXJhdGlvbnMuIERlZmF1bHRzIHRvIDAuIENhbiBiZSBhbnkgK3ZlIG9yIC12ZSBudW1iZXIuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE51bWJlcnxGdW5jdGlvbn0gICBgb3B0aW9ucy52YWx1ZWAgVGhlIGBjYWxsYmFja2AgaXMgb25seSB0cmlnZ2VyZWQgaWYgdGhpcyBjb25kaXRpb24gbWF0Y2hlcy4gU2VlIGV4YW1wbGVzIGZvciBkZXRhaWxzLlxuICAgICAqXG4gICAgICovXG4gICAgc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9waWMsIGNhbGxiYWNrLCBjb250ZXh0LCBvcHRpb25zKSB7XG5cbiAgICAgICAgdmFyIHRvcGljcyA9IFtdLmNvbmNhdCh0b3BpYyk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBzdWJzY3JpcHRpb25JZHMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuICAgICAgICBvcHRzLnRyYW5zcG9ydC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkLmVhY2godG9waWNzLCBmdW5jdGlvbiAoaW5kZXgsIHRvcGljKSB7XG4gICAgICAgICAgICAgICAgdG9waWMgPSBtYWtlTmFtZShvcHRzLmJhc2UsIG9wdHMudG9waWNSZXNvbHZlcih0b3BpYykpO1xuICAgICAgICAgICAgICAgIHN1YnNjcmlwdGlvbklkcy5wdXNoKG9wdHMudHJhbnNwb3J0LnN1YnNjcmliZSh0b3BpYywgY2FsbGJhY2spKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChzdWJzY3JpcHRpb25JZHNbMV0gPyBzdWJzY3JpcHRpb25JZHMgOiBzdWJzY3JpcHRpb25JZHNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBQdWJsaXNoIGRhdGEgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICAvLyBTZW5kIGRhdGEgdG8gYWxsIHN1YnNjcmliZXJzIG9mIHRoZSAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsIHsgY29tcGxldGVkOiBmYWxzZSB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bi92YXJpYWJsZXMnIHRvcGljXG4gICAgICogICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcycsIHsgcHJpY2U6IDUwIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRvcGljYCBUb3BpYyB0byBwdWJsaXNoIHRvLlxuICAgICAqIEBwYXJhbSAgeyp9IGBkYXRhYCAgRGF0YSB0byBwdWJsaXNoIHRvIHRvcGljLlxuICAgICAqXG4gICAgICovXG4gICAgcHVibGlzaDogZnVuY3Rpb24gKHRvcGljLCBkYXRhKSB7XG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgcmV0dXJuT2JqcyA9IFtdO1xuICAgICAgICB2YXIgb3B0cyA9IG1lLmNoYW5uZWxPcHRpb25zO1xuXG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBpZiAodG9waWMuY2hhckF0KHRvcGljLmxlbmd0aCAtIDEpID09PSAnKicpIHtcbiAgICAgICAgICAgICAgICAgICAgdG9waWMgPSB0b3BpYy5yZXBsYWNlKC9cXCorJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdZb3UgY2FuIGNhbm5vdCBwdWJsaXNoIHRvIGNoYW5uZWxzIHdpdGggd2lsZGNhcmRzLiBQdWJsaXNoaW5nIHRvICcsIHRvcGljLCAnaW5zdGVhZCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpzLnB1c2gob3B0cy50cmFuc3BvcnQucHVibGlzaCh0b3BpYywgZGF0YSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKHJldHVybk9ianNbMV0gPyByZXR1cm5PYmpzIDogcmV0dXJuT2Jqc1swXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVuc3Vic2NyaWJlIGZyb20gY2hhbmdlcyB0byBhIHRvcGljLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgY3MudW5zdWJzY3JpYmUoJ3NhbXBsZVRva2VuJyk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRva2VuYCBUaGUgdG9rZW4gZm9yIHRvcGljIGlzIHJldHVybmVkIHdoZW4geW91IGluaXRpYWxseSBzdWJzY3JpYmUuIFBhc3MgaXQgaGVyZSB0byB1bnN1YnNjcmliZSBmcm9tIHRoYXQgdG9waWMuXG4gICAgICovXG4gICAgdW5zdWJzY3JpYmU6IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICB0aGlzLmNoYW5uZWxPcHRpb25zLnRyYW5zcG9ydC51bnN1YnNjcmliZSh0b2tlbik7XG4gICAgICAgIHJldHVybiB0b2tlbjtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICpcbiAgICAgKiBTdXBwb3J0ZWQgZXZlbnRzIGFyZTogYGNvbm5lY3RgLCBgZGlzY29ubmVjdGAsIGBzdWJzY3JpYmVgLCBgdW5zdWJzY3JpYmVgLCBgcHVibGlzaGAsIGBlcnJvcmAuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqL1xuICAgIG9uOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vbi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdG9wIGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqL1xuICAgIG9mZjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub2ZmLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZXZlbnRzIGFuZCBleGVjdXRlIGhhbmRsZXJzLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqL1xuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENoYW5uZWw7XG4iLCIvKipcbiAqIEBjbGFzcyBDb25maWd1cmF0aW9uU2VydmljZVxuICpcbiAqIEFsbCBzZXJ2aWNlcyB0YWtlIGluIGEgY29uZmlndXJhdGlvbiBzZXR0aW5ncyBvYmplY3QgdG8gY29uZmlndXJlIHRoZW1zZWx2ZXMuIEEgSlMgaGFzaCB7fSBpcyBhIHZhbGlkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCBidXQgb3B0aW9uYWxseSB5b3UgY2FuIHVzZSB0aGUgY29uZmlndXJhdGlvbiBzZXJ2aWNlIHRvIHRvZ2dsZSBjb25maWdzIGJhc2VkIG9uIHRoZSBlbnZpcm9ubWVudFxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgdmFyIGNzID0gcmVxdWlyZSgnY29uZmlndXJhdGlvbi1zZXJ2aWNlJykoe1xuICogICAgICAgICAgZGV2OiB7IC8vZW52aXJvbm1lbnRcbiAgICAgICAgICAgICAgICBwb3J0OiAzMDAwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdsb2NhbGhvc3QnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHByb2Q6IHtcbiAgICAgICAgICAgICAgICBwb3J0OiA4MDgwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgICAgICAgICBsb2dMZXZlbDogJ25vbmUnXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbG9nTGV2ZWw6ICdERUJVRycgLy9nbG9iYWxcbiAqICAgICB9KTtcbiAqXG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudignZGV2Jyk7XG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudigncHJvZCcpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnbm9uZSdcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHVybFNlcnZpY2UgPSByZXF1aXJlKCcuL3VybC1jb25maWctc2VydmljZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IEVudmlyb25tZW50c1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgbG9nTGV2ZWw6ICdOT05FJ1xuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHNlcnZpY2VPcHRpb25zLnNlcnZlciA9IHVybFNlcnZpY2Uoc2VydmljZU9wdGlvbnMuc2VydmVyKTtcblxuICAgIHJldHVybiB7XG5cbiAgICAgICAgZGF0YTogc2VydmljZU9wdGlvbnMsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgZW52aXJvbm1lbnQga2V5IHRvIGdldCBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbVxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGVudlxuICAgICAgICAgKi9cbiAgICAgICAgc2V0RW52OiBmdW5jdGlvbiAoZW52KSB7XG5cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHByb3BlcnR5IG9wdGlvbmFsXG4gICAgICAgICAqIEByZXR1cm4geyp9ICAgICAgICAgIFZhbHVlIG9mIHByb3BlcnR5IGlmIHNwZWNpZmllZCwgdGhlIGVudGlyZSBjb25maWcgb2JqZWN0IG90aGVyd2lzZVxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9uc1twcm9wZXJ0eV07XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5IGlmIGEga2V5IGlzIHByb3ZpZGVkLCBzZXQgYSBrZXkgdG8gdGhhdCB2YWx1ZS4gT3RoZXJ3aXNlIG1lcmdlIG9iamVjdCB3aXRoIGN1cnJlbnQgY29uZmlnXG4gICAgICAgICAqIEBwYXJhbSAgeyp9IHZhbHVlICB2YWx1ZSBmb3IgcHJvdmlkZWQga2V5XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9uc1trZXldID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9O1xufTtcblxuIiwiLyoqXG4gKiAjI0RhdGEgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgRGF0YSBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgbWFuaXB1bGF0ZSBkYXRhIHJlbGF0ZWQgdG8gYW55IG9mIHlvdXIgcHJvamVjdHMuIERhdGEgYXJlIG9yZ2FuaXplZCBpbiBjb2xsZWN0aW9ucy4gRWFjaCBjb2xsZWN0aW9uIGNvbnRhaW5zIGEgZG9jdW1lbnQ7IGVhY2ggZWxlbWVudCBvZiB0aGlzIHRvcC1sZXZlbCBkb2N1bWVudCBpcyBhIEpTT04gb2JqZWN0LiAoU2VlIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gb24gdGhlIHVuZGVybHlpbmcgW0RhdGEgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvZGF0YV9hcGkvKS4pXG4gKlxuICogQWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgRGF0YSBBUEkgU2VydmljZSBkZWZhdWx0cy4gSW4gcGFydGljdWxhciwgdGhlcmUgYXJlIHRocmVlIHJlcXVpcmVkIHBhcmFtZXRlcnMgd2hlbiB5b3UgaW5zdGFudGlhdGUgdGhlIERhdGEgU2VydmljZTpcbiAqXG4gKiAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgcHJvamVjdGA6IEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICogKiBgcm9vdGA6IFRoZSB0aGUgbmFtZSBvZiB0aGUgY29sbGVjdGlvbi4gSWYgeW91IGhhdmUgbXVsdGlwbGUgY29sbGVjdGlvbnMgd2l0aGluIGVhY2ggb2YgeW91ciBwcm9qZWN0cywgeW91IGNhbiBhbHNvIHBhc3MgdGhlIGNvbGxlY3Rpb24gbmFtZSBhcyBhbiBvcHRpb24gZm9yIGVhY2ggY2FsbC5cbiAqXG4gKiAgICAgICB2YXIgZHMgPSBuZXcgRi5zZXJ2aWNlLkRhdGEoe1xuICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgIHJvb3Q6ICdzdXJ2ZXktcmVzcG9uc2VzJyxcbiAqICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBkcy5zYXZlQXMoJ3VzZXIxJyxcbiAqICAgICAgICAgIHsgJ3F1ZXN0aW9uMSc6IDIsICdxdWVzdGlvbjInOiAxMCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiBmYWxzZSwgJ3F1ZXN0aW9uNCc6ICdzb21ldGltZXMnIH0gKTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjInLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMywgJ3F1ZXN0aW9uMic6IDgsXG4gKiAgICAgICAgICAncXVlc3Rpb24zJzogdHJ1ZSwgJ3F1ZXN0aW9uNCc6ICdhbHdheXMnIH0gKTtcbiAqICAgICAgIGRzLnF1ZXJ5KCcnLHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICpcbiAqIE5vdGUgdGhhdCBpbiBhZGRpdGlvbiB0byB0aGUgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgcm9vdGAsIHRoZSBEYXRhIFNlcnZpY2UgcGFyYW1ldGVycyBvcHRpb25hbGx5IGluY2x1ZGUgYSBgc2VydmVyYCBvYmplY3QsIHdob3NlIGBob3N0YCBmaWVsZCBjb250YWlucyB0aGUgVVJJIG9mIHRoZSBGb3JpbyBzZXJ2ZXIuIFRoaXMgaXMgYXV0b21hdGljYWxseSBzZXQsIGJ1dCB5b3UgY2FuIHBhc3MgaXQgZXhwbGljaXRseSBpZiBkZXNpcmVkLiBJdCBpcyBtb3N0IGNvbW1vbmx5IHVzZWQgZm9yIGNsYXJpdHkgd2hlbiB5b3UgYXJlIFtob3N0aW5nIGFuIEVwaWNlbnRlciBwcm9qZWN0IG9uIHlvdXIgb3duIHNlcnZlcl0oLi4vLi4vLi4vaG93X3RvL3NlbGZfaG9zdGluZy8pLlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogTmFtZSBvZiBjb2xsZWN0aW9uLiBEZWZhdWx0cyB0byBgL2AsIHRoYXQgaXMsIHRoZSByb290IGxldmVsIG9mIHlvdXIgcHJvamVjdCBhdCBgZm9yaW8uY29tL2FwcC95b3VyLWFjY291bnQtaWQveW91ci1wcm9qZWN0LWlkL2AuIFJlcXVpcmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcm9vdDogJy8nLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIG9wZXJhdGlvbnMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIGRvbWFpbjogJ2ZvcmlvLmNvbScsXG5cbiAgICAgICAgLy9PcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoa2V5LCByb290KSB7XG4gICAgICAgIGlmICghcm9vdCkge1xuICAgICAgICAgICAgcm9vdCA9IHNlcnZpY2VPcHRpb25zLnJvb3Q7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdkYXRhJykgKyBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKHJvb3QpO1xuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICB1cmwrPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBUaGUgbmFtZSBvZiB0aGUgZG9jdW1lbnQgdG8gc2VhcmNoLiBQYXNzIHRoZSBlbXB0eSBzdHJpbmcgKCcnKSB0byBzZWFyY2ggdGhlIGVudGlyZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHF1ZXJ5YCBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgdG8gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHtxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBrZXlgIElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWx1ZWAgKE9wdGlvbmFsKSBUaGUgZGF0YSB0byBzYXZlLiBJZiBga2V5YCBpcyBhIHN0cmluZywgdGhpcyBpcyB0aGUgdmFsdWUgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgdmFsdWUocykgdG8gc2F2ZSBhcmUgYWxyZWFkeSBwYXJ0IG9mIGBrZXlgIGFuZCB0aGlzIGFyZ3VtZW50IGlzIG5vdCByZXF1aXJlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhIG5hbWVkIGRvY3VtZW50IG9yIGVsZW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHNlcGFyYXRlbHkgaW4gY29uZmlndXJhdGlvbiBvcHRpb25zLCBlaXRoZXIgYXMgcGFydCBvZiB0aGUgY2FsbCBvciBhcyBwYXJ0IG9mIHRoZSBpbml0aWFsaXphdGlvbiBvZiBkcy5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYGtleWAgSWQgb2YgdGhlIGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYGtleWAgVGhlIGlkIG9mIHRoZSBkYXRhIHRvIHJldHVybi4gQ2FuIGJlIHRoZSBpZCBvZiBhIGRvY3VtZW50LCBvciBhIHBhdGggdG8gZGF0YSB3aXRoaW4gdGhhdCBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChrZXksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBkYXRhIGZyb20gY29sbGVjdGlvbi4gT25seSBkb2N1bWVudHMgKHRvcC1sZXZlbCBlbGVtZW50cyBpbiBlYWNoIGNvbGxlY3Rpb24pIGNhbiBiZSBkZWxldGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgZHMucmVtb3ZlKCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xBcnJheX0gYGtleXNgIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBwYXJhbXM7XG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KGtleXMpKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBpZDoga2V5cyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSAnJztcbiAgICAgICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5cywgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFcGljZW50ZXIgZG9lc24ndCBhbGxvdyBudWtpbmcgY29sbGVjdGlvbnNcbiAgICAgICAgLy8gICAgIC8qKlxuICAgICAgICAvLyAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgLy8gICAgICAqIEByZXR1cm4gbnVsbFxuICAgICAgICAvLyAgICAgICovXG4gICAgICAgIC8vICAgICBkZXN0cm95OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgnJywgb3B0aW9ucyk7XG4gICAgICAgIC8vICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyNNZW1iZXIgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgTWVtYmVyIEFQSSBBZGFwdGVyIHByb3ZpZGVzIG1ldGhvZHMgdG8gbG9vayB1cCBpbmZvcm1hdGlvbiBhYm91dCBlbmQgdXNlcnMgZm9yIHlvdXIgcHJvamVjdCBhbmQgaG93IHRoZXkgYXJlIGRpdmlkZWQgYWNyb3NzIGdyb3Vwcy4gSXQgaXMgYmFzZWQgb24gcXVlcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW01lbWJlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvbWVtYmVyLykuXG4gKlxuICogVGhpcyBpcyBvbmx5IG5lZWRlZCBmb3IgQXV0aGVudGljYXRlZCBwcm9qZWN0cywgdGhhdCBpcywgdGVhbSBwcm9qZWN0cyB3aXRoIFtlbmQgdXNlcnMgYW5kIGdyb3Vwc10oLi4vLi4vLi4vZ3JvdXBzX2FuZF9lbmRfdXNlcnMvKS4gRm9yIGV4YW1wbGUsIGlmIHNvbWUgb2YgeW91ciBlbmQgdXNlcnMgYXJlIGZhY2lsaXRhdG9ycywgb3IgaWYgeW91ciBlbmQgdXNlcnMgc2hvdWxkIGJlIHRyZWF0ZWQgZGlmZmVyZW50bHkgYmFzZWQgb24gd2hpY2ggZ3JvdXAgdGhleSBhcmUgaW4sIHVzZSB0aGUgTWVtYmVyIEFQSSB0byBmaW5kIHRoYXQgaW5mb3JtYXRpb24uXG4gKlxuICogICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gKiAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICdiNmIzMTNhMy1hYjg0LTQ3OWMtYmFlYS0yMDZmNmJmZjMzNycgfSk7XG4gKiAgICAgIG1hLmdldEdyb3VwRGV0YWlscyh7IGdyb3VwSWQ6ICcwMGI1MzMwOC05ODMzLTQ3ZjItYjIxZS0xMjc4YzA3ZDUzYjgnIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGFwaUVuZHBvaW50ID0gJ21lbWJlci9sb2NhbCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciB1c2VyIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBncm91cCBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuIE5vdGUgdGhhdCB0aGlzIGlzIHRoZSBncm91cCAqaWQqLCBub3QgdGhlIGdyb3VwICpuYW1lKi5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGdyb3VwSWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucywgc2VydmljZU9wdGlvbnMpO1xuXG4gICAgdmFyIGdldEZpbmFsUGFyYW1zID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBwYXRjaFVzZXJBY3RpdmVGaWVsZCA9IGZ1bmN0aW9uIChwYXJhbXMsIGFjdGl2ZSwgb3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBwYXJhbXMuZ3JvdXBJZCArICcvJyArIHBhcmFtcy51c2VySWRcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goeyBhY3RpdmU6IGFjdGl2ZSB9LCBodHRwT3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBhbGwgb2YgdGhlIGdyb3VwIG1lbWJlcnNoaXBzIGZvciBvbmUgZW5kIHVzZXIuIFRoZSBtZW1iZXJzaGlwIGRldGFpbHMgYXJlIHJldHVybmVkIGluIGFuIGFycmF5LCB3aXRoIG9uZSBlbGVtZW50IChncm91cCByZWNvcmQpIGZvciBlYWNoIGdyb3VwIHRvIHdoaWNoIHRoZSBlbmQgdXNlciBiZWxvbmdzLlxuICAgICAgICAqXG4gICAgICAgICogSW4gdGhlIG1lbWJlcnNoaXAgYXJyYXksIGVhY2ggZ3JvdXAgcmVjb3JkIGluY2x1ZGVzIHRoZSBncm91cCBpZCwgcHJvamVjdCBpZCwgYWNjb3VudCAodGVhbSkgaWQsIGFuZCBhbiBhcnJheSBvZiBtZW1iZXJzLiBIb3dldmVyLCBvbmx5IHRoZSB1c2VyIHdob3NlIHVzZXJJZCBpcyBpbmNsdWRlZCBpbiB0aGUgY2FsbCBpcyBsaXN0ZWQgaW4gdGhlIG1lbWJlcnMgYXJyYXkgKHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGVyZSBhcmUgb3RoZXIgbWVtYmVycyBpbiB0aGlzIGdyb3VwKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcignNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24obWVtYmVyc2hpcHMpe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPG1lbWJlcnNoaXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cobWVtYmVyc2hpcHNbaV0uZ3JvdXBJZCk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gYHBhcmFtc2AgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlci4gQWx0ZXJuYXRpdmVseSwgYW4gb2JqZWN0IHdpdGggZmllbGQgYHVzZXJJZGAgYW5kIHZhbHVlIHRoZSB1c2VyIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRHcm91cHNGb3JVc2VyOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB1c2VySWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ2V0UGFybXMgPSBpc1N0cmluZyA/IHsgdXNlcklkOiBwYXJhbXMgfSA6IF9waWNrKG9ialBhcmFtcywgJ3VzZXJJZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldFBhcm1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBvbmUgZ3JvdXAsIGluY2x1ZGluZyBhbiBhcnJheSBvZiBhbGwgaXRzIG1lbWJlcnMuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3VwRGV0YWlscygnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZ3JvdXApe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPGdyb3VwLm1lbWJlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhncm91cC5tZW1iZXJzW2ldLnVzZXJOYW1lKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIH1cbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoeyBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fSBgcGFyYW1zYCBUaGUgZ3JvdXAgaWQuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGBncm91cElkYCBhbmQgdmFsdWUgdGhlIGdyb3VwIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0R3JvdXBEZXRhaWxzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMuZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZ3JvdXBJZCBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBncm91cElkID0gaXNTdHJpbmcgPyBwYXJhbXMgOiBvYmpQYXJhbXMuZ3JvdXBJZDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIGdyb3VwSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgYWN0aXZlYC4gQWN0aXZlIGVuZCB1c2VycyBjYW4gYmUgYXNzaWduZWQgdG8gW3dvcmxkc10oLi4vd29ybGQtbWFuYWdlci8pIGluIG11bHRpcGxheWVyIGdhbWVzIGR1cmluZyBhdXRvbWF0aWMgYXNzaWdubWVudC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEubWFrZVVzZXJBY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIG1ha2VVc2VyQWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCB0cnVlLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBTZXQgYSBwYXJ0aWN1bGFyIGVuZCB1c2VyIGFzIGBpbmFjdGl2ZWAuIEluYWN0aXZlIGVuZCB1c2VycyBhcmUgbm90IGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VySW5hY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggdGhpcyBlbmQgdXNlciBiZWxvbmdzLCBhbmQgaW4gd2hpY2ggdGhlIGVuZCB1c2VyIHNob3VsZCBiZWNvbWUgaW5hY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckluYWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCBmYWxzZSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI1J1biBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBSdW4gQVBJIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBwZXJmb3JtIGNvbW1vbiB0YXNrcyBhcm91bmQgY3JlYXRpbmcgYW5kIHVwZGF0aW5nIHJ1bnMsIHZhcmlhYmxlcywgYW5kIGRhdGEuXG4gKlxuICogV2hlbiBidWlsZGluZyBpbnRlcmZhY2VzIHRvIHNob3cgcnVuIG9uZSBhdCBhIHRpbWUgKGFzIGZvciBzdGFuZGFyZCBlbmQgdXNlcnMpLCB0eXBpY2FsbHkgeW91IGZpcnN0IGluc3RhbnRpYXRlIGEgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGFuZCB0aGVuIGFjY2VzcyB0aGUgUnVuIFNlcnZpY2UgdGhhdCBpcyBhdXRvbWF0aWNhbGx5IHBhcnQgb2YgdGhlIG1hbmFnZXIsIHJhdGhlciB0aGFuIGluc3RhbnRpYXRpbmcgdGhlIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LiBUaGlzIGlzIGJlY2F1c2UgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLlxuICpcbiAqIEhvd2V2ZXIsIG1hbnkgb2YgdGhlIEVwaWNlbnRlciBzYW1wbGUgcHJvamVjdHMgdXNlIGEgUnVuIFNlcnZpY2UsIGJlY2F1c2UgZ2VuZXJhbGx5IHRoZSBzYW1wbGUgcHJvamVjdHMgYXJlIHBsYXllZCBpbiBvbmUgZW5kIHVzZXIgc2Vzc2lvbiBhbmQgZG9uJ3QgY2FyZSBhYm91dCBydW4gc3RhdGVzIG9yIFtydW4gc3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKS4gVGhlIFJ1biBBUEkgU2VydmljZSBpcyBhbHNvIHVzZWZ1bCBmb3IgYnVpbGRpbmcgYW4gaW50ZXJmYWNlIGZvciBhIGZhY2lsaXRhdG9yLCBiZWNhdXNlIGl0IG1ha2VzIGl0IGVhc3kgdG8gbGlzdCBkYXRhIGFjcm9zcyBtdWx0aXBsZSBydW5zICh1c2luZyB0aGUgYGZpbHRlcigpYCBhbmQgYHF1ZXJ5KClgIG1ldGhvZHMpLlxuICpcbiAqIFRvIHVzZSB0aGUgUnVuIEFQSSBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKlxuICogRm9yIGV4YW1wbGUsXG4gKlxuICogICAgICAgdmFyIHJzID0gbmV3IEYuc2VydmljZS5SdW4oe1xuICogICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgIH0pO1xuICogICAgICBycy5jcmVhdGUoJ3N1cHBseV9jaGFpbl9nYW1lLnB5JykudGhlbihmdW5jdGlvbihydW4pIHtcbiAqICAgICAgICAgICAgIHJzLmRvKCdzb21lT3BlcmF0aW9uJyk7XG4gKiAgICAgIH0pO1xuICpcbiAqXG4gKiBBZGRpdGlvbmFsbHksIGFsbCBBUEkgY2FsbHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFJ1biBBUEkgU2VydmljZSBkZWZhdWx0cyBsaXN0ZWQgYmVsb3cuXG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGBtb2RlbGAsIHRoZSBSdW4gU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKlxuICogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiAqICAgICAgICAgICBydW46IHtcbiAqICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseV9jaGFpbl9nYW1lLnB5JyxcbiAqICAgICAgICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICAgICAgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBybS5nZXRSdW4oKVxuICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBSdW4gU2VydmljZSxcbiAqICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4gKiAgICAgICAgICAgICAgIHZhciBycyA9IHJtLnJ1bjtcbiAqICAgICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgIH0pXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgVmFyaWFibGVzU2VydmljZSA9IHJlcXVpcmUoJy4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8IHN0b3JlLmdldCgnZXBpY2VudGVyLnRva2VuJykgfHwgJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgcnVucy4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlci5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRmxhZyBkZXRlcm1pbmVzIGlmIGBYLUF1dG9SZXN0b3JlOiB0cnVlYCBoZWFkZXIgaXMgc2VudCB0byBFcGljZW50ZXIuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBhdXRvUmVzdG9yZTogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuICAgIHVybENvbmZpZy5nZXRGaWx0ZXJVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJyk7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBxdXRpbC50b01hdHJpeEZvcm1hdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpO1xuXG4gICAgICAgIGlmIChmaWx0ZXIpIHtcbiAgICAgICAgICAgIHVybCArPSBmaWx0ZXIgKyAnLyc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmZpbHRlcjtcbiAgICAgICAgLy8gVGhlIHNlbWljb2xvbiBzZXBhcmF0ZWQgZmlsdGVyIGlzIHVzZWQgd2hlbiBmaWx0ZXIgaXMgYW4gb2JqZWN0XG4gICAgICAgIHZhciBpc0ZpbHRlclJ1bklkID0gZmlsdGVyICYmICQudHlwZShmaWx0ZXIpID09PSAnc3RyaW5nJztcbiAgICAgICAgaWYgKHNlcnZpY2VPcHRpb25zLmF1dG9SZXN0b3JlICYmIGlzRmlsdGVyUnVuSWQpIHtcbiAgICAgICAgICAgIC8vIEJ5IGRlZmF1bHQgYXV0b3JlcGxheSB0aGUgcnVuIGJ5IHNlbmRpbmcgdGhpcyBoZWFkZXIgdG8gZXBpY2VudGVyXG4gICAgICAgICAgICAvLyBodHRwczovL2ZvcmlvLmNvbS9lcGljZW50ZXIvZG9jcy9wdWJsaWMvcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNyZXRyaWV2aW5nXG4gICAgICAgICAgICB2YXIgYXV0b3Jlc3RvcmVPcHRzID0ge1xuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJ1gtQXV0b1Jlc3RvcmUnOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBhdXRvcmVzdG9yZU9wdHMsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgc2V0RmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBmaWx0ZXIgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgdXJsQ29uZmlnOiB1cmxDb25maWcsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyZWF0ZSBhIG5ldyBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIE5PVEU6IFR5cGljYWxseSB0aGlzIGlzIG5vdCB1c2VkISBVc2UgYFJ1bk1hbmFnZXIuZ2V0UnVuKClgIHdpdGggYSBgc3RyYXRlZ3lgIG9mIGBhbHdheXMtbmV3YCwgb3IgdXNlIGBSdW5NYW5hZ2VyLnJlc2V0KClgLiBTZWUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHJzLmNyZWF0ZSgnaGVsbG9fd29ybGQuamwnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYHBhcmFtc2AgSWYgYSBzdHJpbmcsIHRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IFttb2RlbCBmaWxlXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4gVGhpcyBpcyB0aGUgb25lIGZpbGUgaW4gdGhlIHByb2plY3QgdGhhdCBleHBsaWNpdGx5IGV4cG9zZXMgdmFyaWFibGVzIGFuZCBtZXRob2RzLCBhbmQgaXQgbXVzdCBiZSBzdG9yZWQgaW4gdGhlIE1vZGVsIGZvbGRlciBvZiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBJZiBhbiBvYmplY3QsIG1heSBpbmNsdWRlIGBtb2RlbGAsIGBzY29wZWAsIGFuZCBgZmlsZXNgLiAoU2VlIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bl9tYW5hZ2VyLykgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gYHNjb3BlYCBhbmQgYGZpbGVzYC4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICpcbiAgICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJykgfSk7XG4gICAgICAgICAgICB2YXIgcnVuQXBpUGFyYW1zID0gWydtb2RlbCcsICdzY29wZScsICdmaWxlcyddO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gdGhpcyBpcyBqdXN0IHRoZSBtb2RlbCBuYW1lXG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBtb2RlbDogcGFyYW1zIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHdoaXRlbGlzdCB0aGUgZmllbGRzIHRoYXQgd2UgYWN0dWFsbHkgY2FuIHNlbmQgdG8gdGhlIGFwaVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgcnVuQXBpUGFyYW1zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGVsZW1lbnRzIG9mIHRoZSBgcXNgIG9iamVjdCBhcmUgQU5EZWQgdG9nZXRoZXIgd2l0aGluIGEgc2luZ2xlIGNhbGwgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZXR1cm5zIHJ1bnMgd2l0aCBzYXZlZCA9IHRydWUgYW5kIHZhcmlhYmxlcy5wcmljZSA+IDEsXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgdmFyaWFibGVzLnByaWNlIGhhcyBiZWVuIHBlcnNpc3RlZCAocmVjb3JkZWQpXG4gICAgICAgICAqICAgICAgLy8gaW4gdGhlIG1vZGVsLlxuICAgICAgICAgKiAgICAgcnMucXVlcnkoe1xuICAgICAgICAgKiAgICAgICAgICAnc2F2ZWQnOiAndHJ1ZScsXG4gICAgICAgICAqICAgICAgICAgICcucHJpY2UnOiAnPjEnXG4gICAgICAgICAqICAgICAgIH0sXG4gICAgICAgICAqICAgICAgIHtcbiAgICAgICAgICogICAgICAgICAgc3RhcnRyZWNvcmQ6IDIsXG4gICAgICAgICAqICAgICAgICAgIGVuZHJlY29yZDogNVxuICAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBxc2AgUXVlcnkgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBRdWVyeWluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXMsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBxczsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFNpbWlsYXIgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJgIEZpbHRlciBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIEZpbHRlcmluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogZnVuY3Rpb24gKGZpbHRlciwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qoc2VydmljZU9wdGlvbnMuZmlsdGVyKSkge1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlcnZpY2VPcHRpb25zLmZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gZmlsdGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBkYXRhIGZvciBhIHNwZWNpZmljIHJ1bi4gVGhpcyBpbmNsdWRlcyBzdGFuZGFyZCBydW4gZGF0YSBzdWNoIGFzIHRoZSBhY2NvdW50LCBtb2RlbCwgcHJvamVjdCwgYW5kIGNyZWF0ZWQgYW5kIGxhc3QgbW9kaWZpZWQgZGF0ZXMuIFRvIHJlcXVlc3Qgc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLCBwYXNzIHRoZW0gYXMgcGFydCBvZiB0aGUgYGZpbHRlcnNgIHBhcmFtZXRlci5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IGlmIHRoZSBydW4gaXMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSksIGFueSBtb2RlbCB2YXJpYWJsZXMgYXJlIGF2YWlsYWJsZTsgaWYgdGhlIHJ1biBpcyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLCBvbmx5IG1vZGVsIHZhcmlhYmxlcyB0aGF0IGhhdmUgYmVlbiBwZXJzaXN0ZWQgJm1kYXNoOyB0aGF0IGlzLCBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwgJm1kYXNoOyBhcmUgYXZhaWxhYmxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgcnMubG9hZCgnYmI1ODk2NzctZDQ3Ni00OTcxLWE2OGUtMGM1OGQxOTFlNDUwJywgeyBpbmNsdWRlOiBbJy5wcmljZScsICcuc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBydW5JRGAgVGhlIHJ1biBpZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJzYCAoT3B0aW9uYWwpIE9iamVjdCBjb250YWluaW5nIGZpbHRlcnMgYW5kIG9wZXJhdGlvbiBtb2RpZmllcnMuIFVzZSBrZXkgYGluY2x1ZGVgIHRvIGxpc3QgbW9kZWwgdmFyaWFibGVzIHRoYXQgeW91IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUgcmVzcG9uc2UuIE90aGVyIGF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAocnVuSUQsIGZpbHRlcnMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmIChydW5JRCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJ1bklEOyAvL3Nob3VsZG4ndCBiZSBhYmxlIHRvIG92ZXItcmlkZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBhdHRyaWJ1dGVzIChkYXRhLCBtb2RlbCB2YXJpYWJsZXMpIG9mIHRoZSBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gYWRkICdjb21wbGV0ZWQnIGZpZWxkIHRvIHJ1biByZWNvcmRcbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBjb21wbGV0ZWQ6IHRydWUgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyB1cGRhdGUgJ3NhdmVkJyBmaWVsZCBvZiBydW4gcmVjb3JkLCBhbmQgdXBkYXRlIHZhbHVlcyBvZiBtb2RlbCB2YXJpYWJsZXMgZm9yIHRoaXMgcnVuXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgc2F2ZWQ6IHRydWUsIHZhcmlhYmxlczogeyBhOiAyMywgYjogMjMgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBhdHRyaWJ1dGVzYCBUaGUgcnVuIGRhdGEgYW5kIHZhcmlhYmxlcyB0byBzYXZlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGF0dHJpYnV0ZXMudmFyaWFibGVzYCBNb2RlbCB2YXJpYWJsZXMgbXVzdCBiZSBpbmNsdWRlZCBpbiBhIGB2YXJpYWJsZXNgIGZpZWxkIHdpdGhpbiB0aGUgYGF0dHJpYnV0ZXNgIG9iamVjdC4gKE90aGVyd2lzZSB0aGV5IGFyZSB0cmVhdGVkIGFzIHJ1biBkYXRhIGFuZCBhZGRlZCB0byB0aGUgcnVuIHJlY29yZCBkaXJlY3RseS4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uIChhdHRyaWJ1dGVzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKGF0dHJpYnV0ZXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBhIG1ldGhvZCBmcm9tIHRoZSBtb2RlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2QgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGBwYXJhbXNgIGFyZ3VtZW50IGlzIG5vcm1hbGx5IGFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byB0aGUgYG9wZXJhdGlvbmAuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXkuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCB5b3UgY2FuIGNvbWJpbmUgdGhlIGBvcGVyYXRpb25gIGFuZCBgcGFyYW1zYCBhcmd1bWVudHMgaW50byBhIHNpbmdsZSBvYmplY3QgaWYgeW91IHByZWZlciwgYXMgaW4gdGhlIGxhc3QgZXhhbXBsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic29sdmVcIiB0YWtlcyBubyBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLmRvKCdzb2x2ZScpO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsIFsnaGVsbG8nXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgJ2hlbGxvJyk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic3VtQXJyYXlcIiB0YWtlcyBvbmUgYXJndW1lbnQsIGFuIGFycmF5XG4gICAgICAgICAqICAgICBycy5kbygnc3VtQXJyYXknLCBbWzQsMiwxXV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImFkZFwiIHRha2VzIHR3byBhcmd1bWVudHMsIGJvdGggaW50ZWdlcnNcbiAgICAgICAgICogICAgIHJzLmRvKHsgbmFtZTonYWRkJywgcGFyYW1zOlsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYG9wZXJhdGlvbmAgTmFtZSBvZiBtZXRob2QuXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBwYXJhbXNgIChPcHRpb25hbCkgQW55IHBhcmFtZXRlcnMgdGhlIG9wZXJhdGlvbiB0YWtlcywgcGFzc2VkIGFzIGFuIGFycmF5LiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LCBhbmQgY2FuIGp1c3QgcGFzcyBpdCBkaXJlY3RseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZG86IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ2RvJywgb3BlcmF0aW9uLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wc0FyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnM7XG4gICAgICAgICAgICBpZiAob3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICAgICAgb3BzQXJncyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9uLCBvcHNBcmdzKTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgcG9zdE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcHJtcyA9IChyZXN1bHQuYXJnc1swXS5sZW5ndGggJiYgKHJlc3VsdC5hcmdzWzBdICE9PSBudWxsICYmIHJlc3VsdC5hcmdzWzBdICE9PSB1bmRlZmluZWQpKSA/IHJlc3VsdC5hcmdzWzBdIDogW107XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgYXJndW1lbnRzOiBwcm1zIH0sICQuZXh0ZW5kKHRydWUsIHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ29wZXJhdGlvbnMvJyArIHJlc3VsdC5vcHNbMF0gKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwsIHNlcXVlbnRpYWxseS5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2RzIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0aWFsaXplXCIgYW5kIFwic29sdmVcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWydpbml0aWFsaXplJywgJ3NvbHZlJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0XCIgYW5kIFwicmVzZXRcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncmVzZXQnLCBwYXJhbXM6IFsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJpbml0XCIgdGFrZXMgdHdvIGFyZ3VtZW50cyxcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJydW5tb2RlbFwiIHRha2VzIG5vbmVcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3J1bm1vZGVsJywgcGFyYW1zOiBbXSB9XSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBvcGVyYXRpb25zYCBJZiBub25lIG9mIHRoZSBtZXRob2RzIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgbWV0aG9kIG5hbWVzIChzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBtZXRob2RzIGRvIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGEgbWV0aG9kIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzZXJpYWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9TaW5nbGVPcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgb3AgPSBvcHMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICB2YXIgYXJnID0gYXJncy5zaGlmdCgpO1xuXG4gICAgICAgICAgICAgICAgbWUuZG8ob3AsIGFyZywge1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob3BzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbCwgZXhlY3V0aW5nIHRoZW0gaW4gcGFyYWxsZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kcyBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJzb2x2ZVwiIGFuZCBcInJlc2V0XCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWydzb2x2ZScsICdyZXNldCddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWyB7IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3N1YnRyYWN0JywgcGFyYW1zOlsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoeyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fSBgb3BlcmF0aW9uc2AgSWYgbm9uZSBvZiB0aGUgbWV0aG9kcyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG1ldGhvZCBuYW1lcyAoYXMgc3RyaW5ncykuIElmIGFueSBvZiB0aGUgbWV0aG9kcyBkbyB0YWtlIHBhcmFtZXRlcnMsIHlvdSBoYXZlIHR3byBvcHRpb25zLiBZb3UgY2FuIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhIG1ldGhvZCBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBwYXNzIGEgc2luZ2xlIG9iamVjdCB3aXRoIHRoZSBtZXRob2QgbmFtZSBhbmQgYSAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFsbGVsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG5cbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcXVldWUgID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaTwgb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcXVldWUucHVzaChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kbyhvcHNbaV0sIGFyZ3NbaV0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICQud2hlbi5hcHBseSh0aGlzLCBxdWV1ZSlcbiAgICAgICAgICAgICAgICAuZG9uZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2Vzcy5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvci5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY1N5bmNBUEkgPSB7XG4gICAgICAgIGdldEN1cnJlbnRDb25maWc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgfSxcbiAgICAgICAgLyoqXG4gICAgICAgICAgKiBSZXR1cm5zIGEgVmFyaWFibGVzIFNlcnZpY2UgaW5zdGFuY2UuIFVzZSB0aGUgdmFyaWFibGVzIGluc3RhbmNlIHRvIGxvYWQsIHNhdmUsIGFuZCBxdWVyeSBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLiBTZWUgdGhlIFtWYXJpYWJsZSBBUEkgU2VydmljZV0oLi4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAgICAgICAgKlxuICAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAgICAgIHZhciB2cyA9IHJzLnZhcmlhYmxlcygpO1xuICAgICAgICAgICogICAgICB2cy5zYXZlKHsgc2FtcGxlX2ludDogNCB9KTtcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBjb25maWdgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAgKi9cbiAgICAgICAgdmFyaWFibGVzOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgdnMgPSBuZXcgVmFyaWFibGVzU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZywge1xuICAgICAgICAgICAgICAgIHJ1blNlcnZpY2U6IHRoaXNcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIHJldHVybiB2cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljU3luY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4gKiAjI1N0YXRlIEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIFN0YXRlIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gcmVwbGF5IG9yIGNsb25lIHJ1bnMuIEl0IGJyaW5ncyBleGlzdGluZywgcGVyc2lzdGVkIHJ1biBkYXRhIGZyb20gdGhlIGRhdGFiYXNlIGJhY2sgaW50byBtZW1vcnksIHVzaW5nIHRoZSBzYW1lIHJ1biBpZCAoYHJlcGxheWApIG9yIGEgbmV3IHJ1biBpZCAoYGNsb25lYCkuIFJ1bnMgbXVzdCBiZSBpbiBtZW1vcnkgaW4gb3JkZXIgZm9yIHlvdSB0byB1cGRhdGUgdmFyaWFibGVzIG9yIGNhbGwgb3BlcmF0aW9ucyBvbiB0aGVtLlxuICpcbiAqIFNwZWNpZmljYWxseSwgdGhlIFN0YXRlIEFQSSBBZGFwdGVyIHdvcmtzIGJ5IFwicmUtcnVubmluZ1wiIHRoZSBydW4gKHVzZXIgaW50ZXJhY3Rpb25zKSBmcm9tIHRoZSBjcmVhdGlvbiBvZiB0aGUgcnVuIHVwIHRvIHRoZSB0aW1lIGl0IHdhcyBsYXN0IHBlcnNpc3RlZCBpbiB0aGUgZGF0YWJhc2UuIFRoaXMgcHJvY2VzcyB1c2VzIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIHJ1bidzIG1vZGVsLiBUaGVyZWZvcmUsIGlmIHRoZSBtb2RlbCBoYXMgY2hhbmdlZCBzaW5jZSB0aGUgb3JpZ2luYWwgcnVuIHdhcyBjcmVhdGVkLCB0aGUgcmV0cmlldmVkIHJ1biB3aWxsIHVzZSB0aGUgbmV3IG1vZGVsIOKAlCBhbmQgbWF5IGVuZCB1cCBoYXZpbmcgZGlmZmVyZW50IHZhbHVlcyBvciBiZWhhdmlvciBhcyBhIHJlc3VsdC4gVXNlIHdpdGggY2FyZSFcbiAqXG4gKiBUbyB1c2UgdGhlIFN0YXRlIEFQSSBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBjYWxsIGl0cyBtZXRob2RzOlxuICpcbiAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJ30pO1xuICpcbiAqIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgcHJvamVjdGAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4gKlxuICovXG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBhcGlFbmRwb2ludCA9ICdtb2RlbC9zdGF0ZSc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgfTtcblxuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcbiAgICB2YXIgcGFyc2VSdW5JZE9yRXJyb3IgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSAmJiBwYXJhbXMucnVuSWQpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbXMucnVuSWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwYXNzIGluIGEgcnVuIGlkJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGF5IGEgcnVuLiBBZnRlciB0aGlzIGNhbGwsIHRoZSBydW4sIHdpdGggaXRzIG9yaWdpbmFsIHJ1biBpZCwgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gKEl0IGNvbnRpbnVlcyB0byBiZSBwZXJzaXN0ZWQgaW50byB0aGUgRXBpY2VudGVyIGRhdGFiYXNlIGF0IHJlZ3VsYXIgaW50ZXJ2YWxzLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJywgc3RvcEJlZm9yZTogJ2NhbGN1bGF0ZVNjb3JlJ30pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBicmluZyBiYWNrIHRvIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBgcGFyYW1zLmV4Y2x1ZGVgIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZXBsYXk6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdyZXBsYXknIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ2xvbmUgYSBnaXZlbiBydW4gYW5kIHJldHVybiBhIG5ldyBydW4gaW4gdGhlIHNhbWUgc3RhdGUgYXMgdGhlIGdpdmVuIHJ1bi5cbiAgICAgICAgKlxuICAgICAgICAqIFRoZSBuZXcgcnVuIGlkIGlzIG5vdyBhdmFpbGFibGUgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIFRoZSBuZXcgcnVuIGluY2x1ZGVzIGEgY29weSBvZiBhbGwgb2YgdGhlIGRhdGEgZnJvbSB0aGUgb3JpZ2luYWwgcnVuLCBFWENFUFQ6XG4gICAgICAgICpcbiAgICAgICAgKiAqIFRoZSBgc2F2ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAuXG4gICAgICAgICogKiBUaGUgYGluaXRpYWxpemVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgbm90IGNvcGllZCBmcm9tIHRoZSBvcmlnaW5hbCBydW4gcmVjb3JkLiBJdCBkZWZhdWx0cyB0byBgZmFsc2VgIGJ1dCBtYXkgY2hhbmdlIHRvIGB0cnVlYCBhcyB0aGUgbmV3IHJ1biBpcyBhZHZhbmNlZC4gRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGhhcyBiZWVuIGEgY2FsbCB0byB0aGUgYHN0ZXBgIGZ1bmN0aW9uIChmb3IgVmVuc2ltIG1vZGVscyksIHRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGlzIHNldCB0byBgdHJ1ZWAuXG4gICAgICAgICogKiBUaGUgYGNyZWF0ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyB0aGUgZGF0ZSBhbmQgdGltZSBhdCB3aGljaCB0aGUgY2xvbmUgd2FzIGNyZWF0ZWQgKG5vdCB0aGUgdGltZSB0aGF0IHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQuKVxuICAgICAgICAqXG4gICAgICAgICogVGhlIG9yaWdpbmFsIHJ1biByZW1haW5zIG9ubHkgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLWRiKS5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5jbG9uZSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnLCBleGNsdWRlOiBbJ2ludGVyaW1DYWxjdWxhdGlvbiddIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBjbG9uZSBmcm9tIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBuZXdseSBjbG9uZWQgcnVuIGlzIGFkdmFuY2VkIG9ubHkgdXAgdG8gdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgdGhpcyBtZXRob2QuXG4gICAgICAgICogQHBhcmFtIHthcnJheX0gYHBhcmFtcy5leGNsdWRlYCAoT3B0aW9uYWwpIEFycmF5IG9mIG1ldGhvZHMgdG8gZXhjbHVkZSB3aGVuIGFkdmFuY2luZyB0aGUgbmV3bHkgY2xvbmVkIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGNsb25lOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcnVuSWQgPSBwYXJzZVJ1bklkT3JFcnJvcihwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgcmVwbGF5T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHJ1bklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgYWN0aW9uOiAnY2xvbmUnIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBlcGlWZXJzaW9uID0gcmVxdWlyZSgnLi4vYXBpLXZlcnNpb24uanNvbicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IHVybHV0aWxzIHRvIGdldCBob3N0LCBzaW5jZSBubyB3aW5kb3cgb24gbm9kZVxuXG4gICAgdmFyIEFQSV9QUk9UT0NPTCA9ICdodHRwcyc7XG4gICAgdmFyIEhPU1RfQVBJX01BUFBJTkcgPSB7XG4gICAgICAgICdmb3Jpby5jb20nOiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICdmb3Jpb2Rldi5jb20nOiAnYXBpLmVwaWNlbnRlci5mb3Jpb2Rldi5jb20nXG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNFeHBvcnRzID0ge1xuICAgICAgICBwcm90b2NvbDogQVBJX1BST1RPQ09MLFxuXG4gICAgICAgIGFwaTogJycsXG5cbiAgICAgICAgaG9zdDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICBpZiAoIWhvc3QgfHwgaG9zdC5pbmRleE9mKCdsb2NhbCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGhvc3QgPSAnZm9yaW8uY29tJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAoSE9TVF9BUElfTUFQUElOR1tob3N0XSkgPyBIT1NUX0FQSV9NQVBQSU5HW2hvc3RdIDogJ2FwaS4nICsgaG9zdDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBhcHBQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gcGF0aCAmJiBwYXRoWzFdIHx8ICcnO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFjY291bnRQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFjY250ID0gJyc7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIGFjY250ID0gcGF0aFsyXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhY2NudDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBwcm9qZWN0UGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwcmogPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIGlmIChwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnKSB7XG4gICAgICAgICAgICAgICAgcHJqID0gcGF0aFszXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBwcmo7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgdmVyc2lvblBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgdmVyc2lvbiA9IGVwaVZlcnNpb24udmVyc2lvbiA/IGVwaVZlcnNpb24udmVyc2lvbiArICcvJyA6ICcnO1xuICAgICAgICAgICAgcmV0dXJuIHZlcnNpb247XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgaXNMb2NhbGhvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICByZXR1cm4gKCFob3N0IHx8IGhvc3QuaW5kZXhPZignbG9jYWwnKSAhPT0gLTEpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGdldEFQSVBhdGg6IGZ1bmN0aW9uIChhcGkpIHtcbiAgICAgICAgICAgIHZhciBQUk9KRUNUX0FQSVMgPSBbJ3J1bicsICdkYXRhJywgJ2ZpbGUnXTtcblxuICAgICAgICAgICAgdmFyIGFwaVBhdGggPSB0aGlzLnByb3RvY29sICsgJzovLycgKyB0aGlzLmhvc3QgKyAnLycgKyB0aGlzLnZlcnNpb25QYXRoICsgYXBpICsgJy8nO1xuXG4gICAgICAgICAgICBpZiAoJC5pbkFycmF5KGFwaSwgUFJPSkVDVF9BUElTKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBhcGlQYXRoICs9IHRoaXMuYWNjb3VudFBhdGggKyAnLycgKyB0aGlzLnByb2plY3RQYXRoICArICcvJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhcGlQYXRoO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHB1YmxpY0V4cG9ydHMsIGNvbmZpZyk7XG4gICAgcmV0dXJuIHB1YmxpY0V4cG9ydHM7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4qICMjVXNlciBBUEkgQWRhcHRlclxuKlxuKiBUaGUgVXNlciBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHJldHJpZXZlIGRldGFpbHMgYWJvdXQgZW5kIHVzZXJzIGluIHlvdXIgdGVhbSAoYWNjb3VudCkuIEl0IGlzIGJhc2VkIG9uIHRoZSBxdWVyeWluZyBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbVXNlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvdXNlci8pLlxuKlxuKiBUbyB1c2UgdGhlIFVzZXIgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHMuXG4qXG4qICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nXG4qICAgICAgIH0pO1xuKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiogICAgICAgdWEuZ2V0KHsgdXNlck5hbWU6ICdqc21pdGgnIH0pO1xuKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4qXG4qIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgdG9rZW5gIGlmIHRoZXkgYXJlIG5vdCBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgY3VycmVudCBjb250ZXh0LlxuKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2Nlc3MgdG9rZW4gdG8gdXNlIHdoZW4gc2VhcmNoaW5nIGZvciBlbmQgdXNlcnMuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgcGFydGljdWxhciBlbmQgdXNlcnMgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIG5hbWUgb3IgdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4gICAgICAgICogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgZmlsdGVyYCBPYmplY3Qgd2l0aCBmaWVsZCBgdXNlck5hbWVgIGFuZCB2YWx1ZSBvZiB0aGUgdXNlcm5hbWUuIEFsdGVybmF0aXZlbHksIG9iamVjdCB3aXRoIGZpZWxkIGBpZGAgYW5kIHZhbHVlIG9mIGFuIGFycmF5IG9mIHVzZXIgaWRzLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWx0ZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciB0b1FGaWx0ZXIgPSBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgLy8gQVBJIG9ubHkgc3VwcG9ydHMgZmlsdGVyaW5nIGJ5IHVzZXJuYW1lIGZvciBub3dcbiAgICAgICAgICAgICAgICBpZiAoZmlsdGVyLnVzZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5xID0gZmlsdGVyLnVzZXJOYW1lO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgdG9JZEZpbHRlcnMgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZCA9ICQuaXNBcnJheShpZCkgPyBpZCA6IFtpZF07XG4gICAgICAgICAgICAgICAgcmV0dXJuICdpZD0nICsgaWQuam9pbignJmlkPScpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIGdldEZpbHRlcnMgPSBbXG4gICAgICAgICAgICAgICAgJ2FjY291bnQ9JyArIGdldE9wdGlvbnMuYWNjb3VudCxcbiAgICAgICAgICAgICAgICB0b0lkRmlsdGVycyhmaWx0ZXIuaWQpLFxuICAgICAgICAgICAgICAgIHF1dGlsLnRvUXVlcnlGb3JtYXQodG9RRmlsdGVyKGZpbHRlcikpXG4gICAgICAgICAgICBdLmpvaW4oJyYnKTtcblxuICAgICAgICAgICAgLy8gc3BlY2lhbCBjYXNlIGZvciBxdWVyaWVzIHdpdGggbGFyZ2UgbnVtYmVyIG9mIGlkc1xuICAgICAgICAgICAgLy8gbWFrZSBpdCBhcyBhIHBvc3Qgd2l0aCBHRVQgc2VtYW50aWNzXG4gICAgICAgICAgICB2YXIgdGhyZXNob2xkID0gMzA7XG4gICAgICAgICAgICBpZiAoZmlsdGVyLmlkICYmICQuaXNBcnJheShmaWx0ZXIuaWQpICYmIGZpbHRlci5pZC5sZW5ndGggPj0gdGhyZXNob2xkKSB7XG4gICAgICAgICAgICAgICAgZ2V0T3B0aW9ucy51cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpICsgJz9fbWV0aG9kPUdFVCc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGlkOiBmaWx0ZXIuaWQgfSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRGaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGEgc2luZ2xlIGVuZCB1c2VyIGluIHlvdXIgdGVhbSwgYmFzZWQgb24gdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRCeUlkOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcHVibGljQVBJLmdldCh7IGlkOiB1c2VySWQgfSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG5cblxuXG5cbiIsIi8qKlxuICpcbiAqICMjVmFyaWFibGVzIEFQSSBTZXJ2aWNlXG4gKlxuICogVXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSB0byByZWFkLCB3cml0ZSwgYW5kIHNlYXJjaCBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLlxuICpcbiAqICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJ1xuICogICAgICAgICAgIH1cbiAqICAgICAgfSk7XG4gKiAgICAgcm0uZ2V0UnVuKClcbiAqICAgICAgIC50aGVuKGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgdmFyIHZzID0gcm0ucnVuLnZhcmlhYmxlcygpO1xuICogICAgICAgICAgdnMuc2F2ZSh7c2FtcGxlX2ludDogNH0pO1xuICogICAgICAgIH0pO1xuICpcbiAqL1xuXG5cbiAndXNlIHN0cmljdCc7XG5cbiB2YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG4gdmFyIHJ1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9ydW4tdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcnVucyBvYmplY3QgdG8gd2hpY2ggdGhlIHZhcmlhYmxlIGZpbHRlcnMgYXBwbHkuIERlZmF1bHRzIHRvIG51bGwuXG4gICAgICAgICAqIEB0eXBlIHtydW5TZXJ2aWNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcnVuU2VydmljZTogbnVsbFxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ3ZhcmlhYmxlcy8nO1xuICAgIH07XG5cbiAgICB2YXIgYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9IHtcbiAgICAgICAgdXJsOiBnZXRVUkxcbiAgICB9O1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICBodHRwLnNwbGl0R2V0ID0gcnV0aWwuc3BsaXRHZXRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB2YWx1ZXMgZm9yIGEgdmFyaWFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMubG9hZCgnc2FtcGxlX2ludCcpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCl7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgY29udGFpbnMgdGhlIHZhbHVlIG9mIHNhbXBsZV9pbnRcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgdmFyaWFibGVgIE5hbWUgb2YgdmFyaWFibGUgdG8gbG9hZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHZhcmlhYmxlLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG91dHB1dE1vZGlmaWVyLCAkLmV4dGVuZCh7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IGdldFVSTCgpICsgdmFyaWFibGUgKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHZhcmlhYmxlcywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxdWVyeWAgb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KFsncHJpY2UnLCAnc2FsZXMnXSlcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgaXMgYW4gb2JqZWN0IHdpdGggdGhlIHZhbHVlcyBvZiB0aGUgcmVxdWVzdGVkIHZhcmlhYmxlczogdmFsLnByaWNlLCB2YWwuc2FsZXNcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoeyBpbmNsdWRlOlsncHJpY2UnLCAnc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IGBxdWVyeWAgVGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgcmVxdWVzdGVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9RdWVyeSBhbmQgb3V0cHV0TW9kaWZpZXIgYXJlIGJvdGggcXVlcnlzdHJpbmdzIGluIHRoZSB1cmw7IG9ubHkgY2FsbGluZyB0aGVtIG91dCBzZXBhcmF0ZWx5IGhlcmUgdG8gYmUgY29uc2lzdGVudCB3aXRoIHRoZSBvdGhlciBjYWxsc1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KHF1ZXJ5KSkge1xuICAgICAgICAgICAgICAgIHF1ZXJ5ID0geyBpbmNsdWRlOiBxdWVyeSB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJC5leHRlbmQocXVlcnksIG91dHB1dE1vZGlmaWVyKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KHF1ZXJ5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgdmFsdWVzIHRvIG1vZGVsIHZhcmlhYmxlcy4gT3ZlcndyaXRlcyBleGlzdGluZyB2YWx1ZXMuIE5vdGUgdGhhdCB5b3UgY2FuIG9ubHkgdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoQW4gYWx0ZXJuYXRlIHdheSB0byB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlzIHRvIGNhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwgYW5kIG1ha2Ugc3VyZSB0aGF0IHRoZSBtZXRob2QgcGVyc2lzdHMgdGhlIHZhcmlhYmxlcy4gU2VlIGBkb2AsIGBzZXJpYWxgLCBhbmQgYHBhcmFsbGVsYCBpbiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgZm9yIGNhbGxpbmcgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMuc2F2ZSgncHJpY2UnLCA0KTtcbiAgICAgICAgICogICAgICB2cy5zYXZlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgdmFyaWFibGVgIEFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgbW9kZWwgdmFyaWFibGVzIGFuZCB0aGUgdmFsdWVzIHRvIHNhdmUuIEFsdGVybmF0aXZlbHksIGEgc3RyaW5nIHdpdGggdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbGAgKE9wdGlvbmFsKSBJZiBwYXNzaW5nIGEgc3RyaW5nIGZvciBgdmFyaWFibGVgLCB1c2UgdGhpcyBhcmd1bWVudCBmb3IgdGhlIHZhbHVlIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uICh2YXJpYWJsZSwgdmFsLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW3ZhcmlhYmxlXSA9IHZhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoLmNhbGwodGhpcywgYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdCBBdmFpbGFibGUgdW50aWwgdW5kZXJseWluZyBBUEkgc3VwcG9ydHMgUFVULiBPdGhlcndpc2Ugc2F2ZSB3b3VsZCBiZSBQVVQgYW5kIG1lcmdlIHdvdWxkIGJlIFBBVENIXG4gICAgICAgIC8vICpcbiAgICAgICAgLy8gICogU2F2ZSB2YWx1ZXMgdG8gdGhlIGFwaS4gTWVyZ2VzIGFycmF5cywgYnV0IG90aGVyd2lzZSBzYW1lIGFzIHNhdmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSB2YXJpYWJsZSBPYmplY3Qgd2l0aCBhdHRyaWJ1dGVzLCBvciBzdHJpbmcga2V5XG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSB2YWwgT3B0aW9uYWwgaWYgcHJldiBwYXJhbWV0ZXIgd2FzIGEgc3RyaW5nLCBzZXQgdmFsdWUgaGVyZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAZXhhbXBsZVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSgncHJpY2UnLCA0KTtcblxuICAgICAgICAvLyBtZXJnZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgLy8gICAgIHZhciBhdHRycztcbiAgICAgICAgLy8gICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIC8vICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgIC8vICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAvLyAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAvLyAgICAgfVxuICAgICAgICAvLyAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAvLyAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICAvLyB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNXb3JsZCBBUEkgQWRhcHRlclxuICpcbiAqIEEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsIC0tIGluY2x1ZGluZyBzZXR0aW5nIHZhcmlhYmxlcywgbWFraW5nIGRlY2lzaW9ucywgYW5kIGNhbGxpbmcgb3BlcmF0aW9ucy4gRm9yIGJ1aWxkaW5nIG11bHRpcGxheWVyIHNpbXVsYXRpb25zIHlvdSB0eXBpY2FsbHkgd2FudCBtdWx0aXBsZSBlbmQgdXNlcnMgdG8gc2hhcmUgdGhlIHNhbWUgc2V0IG9mIGludGVyYWN0aW9ucywgYW5kIHdvcmsgd2l0aGluIGEgY29tbW9uIHN0YXRlLiBFcGljZW50ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUgXCJ3b3JsZHNcIiB0byBoYW5kbGUgc3VjaCBjYXNlcy4gT25seSBbdGVhbSBwcm9qZWN0c10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIGNhbiBiZSBtdWx0aXBsYXllci5cbiAqXG4gKiBUaGUgV29ybGQgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUsIGFjY2VzcywgYW5kIG1hbmlwdWxhdGUgbXVsdGlwbGF5ZXIgd29ybGRzIHdpdGhpbiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBZb3UgY2FuIHVzZSB0aGlzIHRvIGFkZCBhbmQgcmVtb3ZlIGVuZCB1c2VycyBmcm9tIHRoZSB3b3JsZCwgYW5kIHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgcmVtb3ZlIHRoZWlyIHJ1bnMuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4gKFRoZSByZWxhdGVkIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyLykgcHJvdmlkZXMgYW4gZWFzeSB3YXkgdG8gYWNjZXNzIHJ1bnMgYW5kIHdvcmxkcyBmb3IgcGFydGljdWxhciBlbmQgdXNlcnMsIHNvIGlzIHR5cGljYWxseSB1c2VkIGluIHBhZ2VzIHRoYXQgZW5kIHVzZXJzIHdpbGwgaW50ZXJhY3Qgd2l0aC4pXG4gKlxuICogQXMgd2l0aCBhbGwgdGhlIG90aGVyIFtBUEkgQWRhcHRlcnNdKC4uLy4uLyksIGFsbCBtZXRob2RzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBXb3JsZCBBUEkgU2VydmljZSBkZWZhdWx0cy5cbiAqXG4gKiBUbyB1c2UgdGhlIFdvcmxkIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSksIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKSwgYW5kIGdyb3VwICgqKkdyb3VwIE5hbWUqKikuXG4gKlxuICogICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gKiAgICAgICB3YS5jcmVhdGUoKVxuICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAqICAgICAgICAgICAgICAvLyBjYWxsIG1ldGhvZHMsIGUuZy4gd2EuYWRkVXNlcnMoKVxuICogICAgICAgICAgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG4vLyB2YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGFwaUJhc2UgPSAnbXVsdGlwbGF5ZXIvJztcbnZhciBhc3NpZ25tZW50RW5kcG9pbnQgPSBhcGlCYXNlICsgJ2Fzc2lnbic7XG52YXIgYXBpRW5kcG9pbnQgPSBhcGlCYXNlICsgJ3dvcmxkJztcbnZhciBwcm9qZWN0RW5kcG9pbnQgPSBhcGlCYXNlICsgJ3Byb2plY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkoeyBzeW5jaHJvbm91czogdHJ1ZSB9KTtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgZ3JvdXA6IHVuZGVmaW5lZCxcblxuICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIHJ1bnMgaW4gdGhpcyB3b3JsZC4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbW9kZWw6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JpdGVyaWEgYnkgd2hpY2ggdG8gZmlsdGVyIHdvcmxkLiBDdXJyZW50bHkgb25seSBzdXBwb3J0cyB3b3JsZC1pZHMgYXMgZmlsdGVycy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlbmllbmNlIGFsaWFzIGZvciBmaWx0ZXJcbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3BcbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMucHJvamVjdCA9IHVybENvbmZpZy5wcm9qZWN0UGF0aDtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBzZXRJZEZpbHRlck9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmlkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gd29ybGQgaWQgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdC4gVGhpcyBjb3VsZCBoYXBwZW4gaWYgdGhlIHVzZXIgaXMgbm90IGFzc2lnbmVkIHRvIGEgd29ybGQgYW5kIGlzIHRyeWluZyB0byB3b3JrIHdpdGggcnVucyBmcm9tIHRoYXQgd29ybGQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAoIW9wdGlvbnMubW9kZWwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gbW9kZWwgc3BlY2lmaWVkIHRvIGdldCB0aGUgY3VycmVudCBydW4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENyZWF0ZXMgYSBuZXcgV29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBVc2luZyB0aGlzIG1ldGhvZCBpcyByYXJlLiBJdCBpcyBtb3JlIGNvbW1vbiB0byBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkgd2hpbGUgeW91IGBhdXRvQXNzaWduKClgIGVuZCB1c2VycyB0byB3b3JsZHMuIChJbiB0aGlzIGNhc2UsIGNvbmZpZ3VyYXRpb24gZGF0YSBmb3IgdGhlIHdvcmxkLCBzdWNoIGFzIHRoZSByb2xlcywgYXJlIHJlYWQgZnJvbSB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9uLCBmb3IgZXhhbXBsZSBieSBgZ2V0UHJvamVjdFNldHRpbmdzKClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSh7XG4gICAgICAgICogICAgICAgICAgIHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddXG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBjcmVhdGUgdGhlIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwYCAoT3B0aW9uYWwpIFRoZSAqKkdyb3VwIE5hbWUqKiB0byBjcmVhdGUgdGhpcyB3b3JsZCB1bmRlci4gT25seSBlbmQgdXNlcnMgaW4gdGhpcyBncm91cCBhcmUgZWxpZ2libGUgdG8gam9pbiB0aGUgd29ybGQuIE9wdGlvbmFsIGhlcmU7IHJlcXVpcmVkIHdoZW4gaW5zdGFudGlhdGluZyB0aGUgc2VydmljZSAoYG5ldyBGLnNlcnZpY2UuV29ybGQoKWApLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfSk7XG4gICAgICAgICAgICB2YXIgd29ybGRBcGlQYXJhbXMgPSBbJ3Njb3BlJywgJ2ZpbGVzJywgJ3JvbGVzJywgJ29wdGlvbmFsUm9sZXMnLCAnbWluVXNlcnMnLCAnZ3JvdXAnLCAnbmFtZSddO1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHdvcmxkQXBpUGFyYW1zKTtcblxuICAgICAgICAgICAgLy8gYWNjb3VudCBhbmQgcHJvamVjdCBnbyBpbiB0aGUgYm9keSwgbm90IGluIHRoZSB1cmxcbiAgICAgICAgICAgICQuZXh0ZW5kKHBhcmFtcywgX3BpY2soc2VydmljZU9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pKTtcblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBVcGRhdGVzIGEgV29ybGQsIGZvciBleGFtcGxlIHRvIHJlcGxhY2UgdGhlIHJvbGVzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgeW91IGNvbXBsZXRlIHdvcmxkIGNvbmZpZ3VyYXRpb24gYXQgdGhlIHByb2plY3QgbGV2ZWwsIHJhdGhlciB0aGFuIGF0IHRoZSB3b3JsZCBsZXZlbC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguIEhvd2V2ZXIsIHRoaXMgbWV0aG9kIGlzIGF2YWlsYWJsZSBpZiB5b3UgbmVlZCB0byB1cGRhdGUgdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBwYXJ0aWN1bGFyIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnVwZGF0ZSh7IHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHVwZGF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMubmFtZWAgQSBzdHJpbmcgaWRlbnRpZmllciBmb3IgdGhlIGxpbmtlZCBlbmQgdXNlcnMsIGZvciBleGFtcGxlLCBcIm5hbWVcIjogXCJPdXIgVGVhbVwiLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHdoaXRlbGlzdCA9IFsncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycyddO1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHVwZGF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zIHx8IHt9LCB3aGl0ZWxpc3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChwYXJhbXMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYW4gZXhpc3Rpbmcgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBUaGlzIGZ1bmN0aW9uIG9wdGlvbmFsbHkgdGFrZXMgb25lIGFyZ3VtZW50LiBJZiB0aGUgYXJndW1lbnQgaXMgYSBzdHJpbmcsIGl0IGlzIHRoZSBpZCBvZiB0aGUgd29ybGQgdG8gZGVsZXRlLiBJZiB0aGUgYXJndW1lbnQgaXMgYW4gb2JqZWN0LCBpdCBpcyB0aGUgb3ZlcnJpZGUgZm9yIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmRlbGV0ZSgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUsIG9yIG9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAob3B0aW9ucyAmJiAodHlwZW9mIG9wdGlvbnMgPT09ICdzdHJpbmcnKSkgPyB7IGZpbHRlcjogb3B0aW9ucyB9IDoge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRlbGV0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGRlbGV0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBjdXJyZW50IGluc3RhbmNlIG9mIHRoZSBXb3JsZCBBUEkgQWRhcHRlciAoaW5jbHVkaW5nIGFsbCBzdWJzZXF1ZW50IGZ1bmN0aW9uIGNhbGxzLCB1bnRpbCB0aGUgY29uZmlndXJhdGlvbiBpcyB1cGRhdGVkIGFnYWluKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoey4uLn0pLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogJzEyMycgfSkuYWRkVXNlcih7IHVzZXJJZDogJzEyMycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgY29uZmlnYCBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gdXNlIGluIHVwZGF0aW5nIGV4aXN0aW5nIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZUNvbmZpZzogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMsIGNvbmZpZyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIExpc3RzIGFsbCB3b3JsZHMgZm9yIGEgZ2l2ZW4gYWNjb3VudCwgcHJvamVjdCwgYW5kIGdyb3VwLiBBbGwgdGhyZWUgYXJlIHJlcXVpcmVkLCBhbmQgaWYgbm90IHNwZWNpZmllZCBhcyBwYXJhbWV0ZXJzLCBhcmUgcmVhZCBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJ0ZWFtMVwiXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5saXN0KCk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJvdGhlci1ncm91cC1uYW1lXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoeyBncm91cDogJ290aGVyLWdyb3VwLW5hbWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBsaXN0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGFsbCB3b3JsZHMgdGhhdCBhbiBlbmQgdXNlciBiZWxvbmdzIHRvIGZvciBhIGdpdmVuIGFjY291bnQgKHRlYW0pLCBwcm9qZWN0LCBhbmQgZ3JvdXAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZ2V0V29ybGRzRm9yVXNlcignYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJylcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZHMgYXJlIGJlaW5nIHJldHJpZXZlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldFdvcmxkc0ZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YXIgZmlsdGVycyA9ICQuZXh0ZW5kKFxuICAgICAgICAgICAgICAgIF9waWNrKGdldE9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pLFxuICAgICAgICAgICAgICAgIHsgdXNlcklkOiB1c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGluZm9ybWF0aW9uIGZvciBhIHNwZWNpZmljIHdvcmxkLiBBbGwgZnVydGhlciBjYWxscyB0byB0aGUgd29ybGQgc2VydmljZSB3aWxsIHVzZSB0aGUgaWQgcHJvdmlkZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgd29ybGRJZGAgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBsb2FkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgd29ybGRpZCB0byBsb2FkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy8nIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQWRkcyBhbiBlbmQgdXNlciBvciBsaXN0IG9mIGVuZCB1c2VycyB0byBhIGdpdmVuIHdvcmxkLiBUaGUgZW5kIHVzZXIgbXVzdCBiZSBhIG1lbWJlciBvZiB0aGUgYGdyb3VwYCB0aGF0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlclxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoWydiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2Vycyh7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdWUCBTYWxlcycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBzZXZlcmFsIHVzZXJzXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgeyB1c2VySWQ6ICdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ1ZQIE1hcmtldGluZycgfSxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgRW5naW5lZXJpbmcnIH1cbiAgICAgICAgKiAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgICAgICAvLyBhZGQgb25lIHVzZXIgdG8gYSBzcGVjaWZpYyB3b3JsZFxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB7IGZpbHRlcjogd29ybGQuaWQgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdHxhcnJheX0gYHVzZXJzYCBVc2VyIGlkLCBhcnJheSBvZiB1c2VyIGlkcywgb2JqZWN0LCBvciBhcnJheSBvZiBvYmplY3RzIG9mIHRoZSB1c2VycyB0byBhZGQgdG8gdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJzLnJvbGVgIFRoZSBgcm9sZWAgdGhlIHVzZXIgc2hvdWxkIGhhdmUgaW4gdGhlIHdvcmxkLiBJdCBpcyB1cCB0byB0aGUgY2FsbGVyIHRvIGVuc3VyZSwgaWYgbmVlZGVkLCB0aGF0IHRoZSBgcm9sZWAgcGFzc2VkIGluIGlzIG9uZSBvZiB0aGUgYHJvbGVzYCBvciBgb3B0aW9uYWxSb2xlc2Agb2YgdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSB3b3JsZCB0byB3aGljaCB0aGUgdXNlcnMgc2hvdWxkIGJlIGFkZGVkLiBJZiBub3Qgc3BlY2lmaWVkLCB0aGUgZmlsdGVyIHBhcmFtZXRlciBvZiB0aGUgYG9wdGlvbnNgIG9iamVjdCBpcyB1c2VkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgYWRkVXNlcnM6IGZ1bmN0aW9uICh1c2Vycywgd29ybGRJZCwgb3B0aW9ucykge1xuXG4gICAgICAgICAgICBpZiAoIXVzZXJzKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhIGxpc3Qgb2YgdXNlcnMgdG8gYWRkIHRvIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBub3JtYWxpemUgdGhlIGxpc3Qgb2YgdXNlcnMgdG8gYW4gYXJyYXkgb2YgdXNlciBvYmplY3RzXG4gICAgICAgICAgICB1c2VycyA9ICQubWFwKFtdLmNvbmNhdCh1c2VycyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KHUpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1ICE9PSAnc3RyaW5nJyAmJiAhaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTb21lIG9mIHRoZSB1c2VycyBpbiB0aGUgbGlzdCBhcmUgbm90IGluIHRoZSB2YWxpZCBmb3JtYXQ6ICcgKyB1KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gaXNPYmplY3QgPyB1IDogeyB1c2VySWQ6IHUgfTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBjaGVjayBpZiBvcHRpb25zIHdlcmUgcGFzc2VkIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHdvcmxkSWQpICYmICFvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHdvcmxkSWQ7XG4gICAgICAgICAgICAgICAgd29ybGRJZCA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICAvLyB3ZSBtdXN0IGhhdmUgb3B0aW9ucyBieSBub3dcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygd29ybGRJZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvdXNlcnMnIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QodXNlcnMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIHJvbGUgb2YgYW4gZW5kIHVzZXIgaW4gYSBnaXZlbiB3b3JsZC4gKFlvdSBjYW4gb25seSB1cGRhdGUgb25lIGVuZCB1c2VyIGF0IGEgdGltZS4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuY3JlYXRlKCkudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgIHdhLnVwZGF0ZVVzZXIoeyB1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCByb2xlOiAnbGVhZGVyJyB9KTtcbiAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHVzZXJgIFVzZXIgb2JqZWN0IHdpdGggYHVzZXJJZGAgYW5kIHRoZSBuZXcgYHJvbGVgLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICghdXNlciB8fCAhdXNlci51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHBhc3MgYSB1c2VySWQgdG8gdXBkYXRlIGZyb20gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcGF0Y2hPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goX3BpY2sodXNlciwgJ3JvbGUnKSwgcGF0Y2hPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZW1vdmVzIGFuIGVuZCB1c2VyIGZyb20gYSBnaXZlbiB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5yZW1vdmVVc2VyKCdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoeyB1c2VySWQ6ICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdHxzdHJpbmd9IGB1c2VyYCBUaGUgYHVzZXJJZGAgb2YgdGhlIHVzZXIgdG8gcmVtb3ZlIGZyb20gdGhlIHdvcmxkLCBvciBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgYHVzZXJJZGAgZmllbGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdXNlciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICB1c2VyID0geyB1c2VySWQ6IHVzZXIgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHJ1biBpZCBvZiBjdXJyZW50IHJ1biBmb3IgdGhlIGdpdmVuIHdvcmxkLiBJZiB0aGUgd29ybGQgZG9lcyBub3QgaGF2ZSBhIHJ1biwgY3JlYXRlcyBhIG5ldyBvbmUgYW5kIHJldHVybnMgdGhlIHJ1biBpZC5cbiAgICAgICAgKlxuICAgICAgICAqIFJlbWVtYmVyIHRoYXQgYSBbcnVuXSguLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwuIEluIHRoZSBjYXNlIG9mIG11bHRpcGxheWVyIHByb2plY3RzLCB0aGUgcnVuIGlzIHNoYXJlZCBieSBhbGwgZW5kIHVzZXJzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRDdXJyZW50UnVuSWQoeyBtb2RlbDogJ21vZGVsLnB5JyB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRSdW5JZDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3J1bicgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoX3BpY2soZ2V0T3B0aW9ucywgJ21vZGVsJyksIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBmb3IgdGhlIGdpdmVuIGVuZCB1c2VyIGluIHRoZSBnaXZlbiBncm91cC4gQnJpbmdzIHRoaXMgbW9zdCByZWNlbnQgd29ybGQgaW50byBtZW1vcnkgaWYgbmVlZGVkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIHVzZSBkYXRhIGZyb20gd29ybGRcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSBjdXJyZW50IChtb3N0IHJlY2VudCkgd29ybGQgaXMgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cC4gSWYgbm90IHByb3ZpZGVkLCBkZWZhdWx0cyB0byB0aGUgZ3JvdXAgdXNlZCB0byBjcmVhdGUgdGhlIHNlcnZpY2UuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRXb3JsZEZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkc0ZvclVzZXIodXNlcklkLCB7IGdyb3VwOiBncm91cE5hbWUgfSlcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGFzc3VtZSB0aGUgbW9zdCByZWNlbnQgd29ybGQgYXMgdGhlICdhY3RpdmUnIHdvcmxkXG4gICAgICAgICAgICAgICAgICAgIHdvcmxkcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7IHJldHVybiBuZXcgRGF0ZShiLmxhc3RNb2RpZmllZCkgLSBuZXcgRGF0ZShhLmxhc3RNb2RpZmllZCk7IH0pO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VycmVudFdvcmxkID0gd29ybGRzWzBdO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50V29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9ICBjdXJyZW50V29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShjdXJyZW50V29ybGQsIG1lKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIHRoZSBjdXJyZW50IHJ1biBmcm9tIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIChOb3RlIHRoYXQgdGhlIHdvcmxkIGlkIHJlbWFpbnMgcGFydCBvZiB0aGUgcnVuIHJlY29yZCwgaW5kaWNhdGluZyB0aGF0IHRoZSBydW4gd2FzIGZvcm1lcmx5IGFuIGFjdGl2ZSBydW4gZm9yIHRoZSB3b3JsZC4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmRlbGV0ZVJ1bignc2FtcGxlLXdvcmxkLWlkJyk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSBgd29ybGRJZGAgb2YgdGhlIHdvcmxkIGZyb20gd2hpY2ggdGhlIGN1cnJlbnQgcnVuIGlzIGJlaW5nIGRlbGV0ZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGVSdW46IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBydW4gZm9yIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgd2EubmV3UnVuRm9yV29ybGQod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgd29ybGRJZCBpbiB3aGljaCB3ZSBjcmVhdGUgdGhlIG5ldyBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIG5ld1J1bkZvcldvcmxkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGN1cnJlbnRSdW5PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IGZpbHRlcjogd29ybGRJZCB8fCBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IoY3VycmVudFJ1bk9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kZWxldGVSdW4od29ybGRJZCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5nZXRDdXJyZW50UnVuSWQoY3VycmVudFJ1bk9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEFzc2lnbnMgZW5kIHVzZXJzIHRvIHdvcmxkcywgY3JlYXRpbmcgbmV3IHdvcmxkcyBhcyBhcHByb3ByaWF0ZSwgYXV0b21hdGljYWxseS4gQXNzaWducyBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cCwgYW5kIGNyZWF0ZXMgbmV3IHdvcmxkcyBhcyBuZWVkZWQgYmFzZWQgb24gdGhlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbiAocm9sZXMsIG9wdGlvbmFsIHJvbGVzLCBhbmQgbWluaW11bSBlbmQgdXNlcnMgcGVyIHdvcmxkKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5hdXRvQXNzaWduKCk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBhdXRvQXNzaWduOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhc3NpZ25tZW50RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBwYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3B0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgcHJvamVjdDogb3B0LnByb2plY3QsXG4gICAgICAgICAgICAgICAgZ3JvdXA6IG9wdC5ncm91cFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKG9wdC5tYXhVc2Vycykge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5tYXhVc2VycyA9IG9wdC5tYXhVc2VycztcbiAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgb3B0KTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBwcm9qZWN0J3Mgd29ybGQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgZXZlcnkgaW50ZXJhY3Rpb24gd2l0aCB5b3VyIHByb2plY3QgdXNlcyB0aGUgc2FtZSBjb25maWd1cmF0aW9uIG9mIGVhY2ggd29ybGQuIEZvciBleGFtcGxlLCBlYWNoIHdvcmxkIGluIHlvdXIgcHJvamVjdCBwcm9iYWJseSBoYXMgdGhlIHNhbWUgcm9sZXMgZm9yIGVuZCB1c2Vycy4gQW5kIHlvdXIgcHJvamVjdCBpcyBwcm9iYWJseSBlaXRoZXIgY29uZmlndXJlZCBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgc2hhcmUgdGhlIHNhbWUgd29ybGQgKGFuZCBydW4pLCBvciBzbWFsbGVyIHNldHMgb2YgZW5kIHVzZXJzIHNoYXJlIHdvcmxkcyDigJQgYnV0IG5vdCBib3RoLlxuICAgICAgICAqXG4gICAgICAgICogKFRoZSBbTXVsdGlwbGF5ZXIgUHJvamVjdCBSRVNUIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL211bHRpcGxheWVyX3Byb2plY3QvKSBhbGxvd3MgeW91IHRvIHNldCB0aGVzZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb25zLiBUaGUgV29ybGQgQWRhcHRlciBzaW1wbHkgcmV0cmlldmVzIHRoZW0sIGZvciBleGFtcGxlIHNvIHRoZXkgY2FuIGJlIHVzZWQgaW4gYXV0by1hc3NpZ25tZW50IG9mIGVuZCB1c2VycyB0byB3b3JsZHMuKVxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmdldFByb2plY3RTZXR0aW5ncygpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHNldHRpbmdzKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5yb2xlcyk7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5vcHRpb25hbFJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0UHJvamVjdFNldHRpbmdzOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChwcm9qZWN0RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIG9wdC51cmwgKz0gW29wdC5hY2NvdW50LCBvcHQucHJvamVjdF0uam9pbignLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQobnVsbCwgb3B0KTtcbiAgICAgICAgfVxuXG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29va2llIFN0b3JhZ2UgU2VydmljZVxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgIHZhciBwZW9wbGUgPSByZXF1aXJlKCdjb29raWUtc3RvcmUnKSh7IHJvb3Q6ICdwZW9wbGUnIH0pO1xuICAgICAgICBwZW9wbGVcbiAgICAgICAgICAgIC5zYXZlKHtsYXN0TmFtZTogJ3NtaXRoJyB9KVxuXG4gKi9cblxuXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5hbWUgb2YgY29sbGVjdGlvblxuICAgICAgICAgKiBAdHlwZSB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHJvb3Q6ICcvJyxcblxuICAgICAgICBkb21haW46ICcuZm9yaW8uY29tJ1xuICAgIH07XG4gICAgdGhpcy5zZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIC8vICogVEJEXG4gICAgICAgIC8vICAqIFF1ZXJ5IGNvbGxlY3Rpb247IHVzZXMgTW9uZ29EQiBzeW50YXhcbiAgICAgICAgLy8gICogQHNlZSAgPFRCRDogRGF0YSBBUEkgVVJMPlxuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IHFzIFF1ZXJ5IEZpbHRlclxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IGxpbWl0ZXJzIEBzZWUgPFRCRDogdXJsIGZvciBsaW1pdHMsIHBhZ2luZyBldGM+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBleGFtcGxlXG4gICAgICAgIC8vICAqICAgICBjcy5xdWVyeShcbiAgICAgICAgLy8gICogICAgICB7IG5hbWU6ICdKb2huJywgY2xhc3NOYW1lOiAnQ1NDMTAxJyB9LFxuICAgICAgICAvLyAgKiAgICAgIHtsaW1pdDogMTB9XG4gICAgICAgIC8vICAqICAgICApXG5cbiAgICAgICAgLy8gcXVlcnk6IGZ1bmN0aW9uIChxcywgbGltaXRlcnMpIHtcblxuICAgICAgICAvLyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGNvb2tpZSB2YWx1ZVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5ICAgSWYgZ2l2ZW4gYSBrZXkgc2F2ZSB2YWx1ZXMgdW5kZXIgaXQsIGlmIGdpdmVuIGFuIG9iamVjdCBkaXJlY3RseSwgc2F2ZSB0byB0b3AtbGV2ZWwgYXBpXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gdmFsdWUgKE9wdGlvbmFsKVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIHNlcnZpY2Ugb3B0aW9uc1xuICAgICAgICAgKlxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgc2F2ZWQgdmFsdWVcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnNldCgncGVyc29uJywgeyBmaXJzdE5hbWU6ICdqb2huJywgbGFzdE5hbWU6ICdzbWl0aCcgfSk7XG4gICAgICAgICAqICAgICBjcy5zZXQoeyBuYW1lOidzbWl0aCcsIGFnZTonMzInIH0pO1xuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHNldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5zZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSBzZXRPcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2V0T3B0aW9ucy5yb290O1xuXG4gICAgICAgICAgICBkb2N1bWVudC5jb29raWUgPSBlbmNvZGVVUklDb21wb25lbnQoa2V5KSArICc9JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuY29kZVVSSUNvbXBvbmVudCh2YWx1ZSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG5cbiAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9hZCBjb29raWUgdmFsdWVcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSAgIElmIGdpdmVuIGEga2V5IHNhdmUgdmFsdWVzIHVuZGVyIGl0LCBpZiBnaXZlbiBhbiBvYmplY3QgZGlyZWN0bHksIHNhdmUgdG8gdG9wLWxldmVsIGFwaVxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgdmFsdWUgc3RvcmVkXG4gICAgICAgICAqXG4gICAgICAgICAqIEBleGFtcGxlXG4gICAgICAgICAqICAgICBjcy5nZXQoJ3BlcnNvbicpO1xuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgY29va2llUmVnID0gbmV3IFJlZ0V4cCgnKD86KD86XnwuKjspXFxcXHMqJyArIGVuY29kZVVSSUNvbXBvbmVudChrZXkpLnJlcGxhY2UoL1tcXC1cXC5cXCtcXCpdL2csICdcXFxcJCYnKSArICdcXFxccypcXFxcPVxcXFxzKihbXjtdKikuKiQpfF4uKiQnKTtcbiAgICAgICAgICAgIHZhciB2YWwgPSBkb2N1bWVudC5jb29raWUucmVwbGFjZShjb29raWVSZWcsICckMScpO1xuICAgICAgICAgICAgdmFsID0gZGVjb2RlVVJJQ29tcG9uZW50KHZhbCkgfHwgbnVsbDtcbiAgICAgICAgICAgIHJldHVybiB2YWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMga2V5IGZyb20gY29sbGVjdGlvblxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGtleSBrZXkgdG8gcmVtb3ZlXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9IGtleSBUaGUga2V5IHJlbW92ZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnJlbW92ZSgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciByZW1PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMuc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9tYWluID0gcmVtT3B0aW9ucy5kb21haW47XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHJlbU9wdGlvbnMucm9vdDtcblxuICAgICAgICAgICAgZG9jdW1lbnQuY29va2llID0gZW5jb2RlVVJJQ29tcG9uZW50KGtleSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICc9OyBleHBpcmVzPVRodSwgMDEgSmFuIDE5NzAgMDA6MDA6MDAgR01UJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGRvbWFpbiA/ICc7IGRvbWFpbj0nICsgZG9tYWluIDogJycpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG4gICAgICAgICAgICByZXR1cm4ga2V5O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIGNvbGxlY3Rpb24gYmVpbmcgcmVmZXJlbmNlZFxuICAgICAgICAgKiBAcmV0dXJuIHsgYXJyYXl9IGtleXMgQWxsIHRoZSBrZXlzIHJlbW92ZWRcbiAgICAgICAgICovXG4gICAgICAgIGRlc3Ryb3k6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhS2V5cyA9IGRvY3VtZW50LmNvb2tpZS5yZXBsYWNlKC8oKD86XnxcXHMqOylbXlxcPV0rKSg/PTt8JCl8Xlxccyp8XFxzKig/OlxcPVteO10qKT8oPzpcXDF8JCkvZywgJycpLnNwbGl0KC9cXHMqKD86XFw9W147XSopPztcXHMqLyk7XG4gICAgICAgICAgICBmb3IgKHZhciBuSWR4ID0gMDsgbklkeCA8IGFLZXlzLmxlbmd0aDsgbklkeCsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvb2tpZUtleSA9IGRlY29kZVVSSUNvbXBvbmVudChhS2V5c1tuSWR4XSk7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmUoY29va2llS2V5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhS2V5cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICAgIERlY2lkZXMgdHlwZSBvZiBzdG9yZSB0byBwcm92aWRlXG4qL1xuXG4ndXNlIHN0cmljdCc7XG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHN0b3JlID0gKGlzTm9kZSkgPyByZXF1aXJlKCcuL3Nlc3Npb24tc3RvcmUnKSA6IHJlcXVpcmUoJy4vY29va2llLXN0b3JlJyk7XG52YXIgc3RvcmUgPSByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHN0b3JlO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgcXV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgIGhlYWRlcnM6IHt9LFxuICAgICAgICBzdGF0dXNDb2RlOiB7XG4gICAgICAgICAgICA0MDQ6ICQubm9vcFxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPTkxZIGZvciBzdHJpbmdzIGluIHRoZSB1cmwuIEFsbCBHRVQgJiBERUxFVEUgcGFyYW1zIGFyZSBydW4gdGhyb3VnaCB0aGlzXG4gICAgICAgICAqIEB0eXBlIHtbdHlwZV0gfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFyYW1ldGVyUGFyc2VyOiBxdXRpbHMudG9RdWVyeUZvcm1hdCxcblxuICAgICAgICAvLyBUbyBhbGxvdyBlcGljZW50ZXIudG9rZW4gYW5kIG90aGVyIHNlc3Npb24gY29va2llcyB0byBiZSBwYXNzZWRcbiAgICAgICAgLy8gd2l0aCB0aGUgcmVxdWVzdHNcbiAgICAgICAgeGhyRmllbGRzOiB7XG4gICAgICAgICAgICB3aXRoQ3JlZGVudGlhbHM6IHRydWVcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciByZXN1bHQgPSBmdW5jdGlvbiAoZCkge1xuICAgICAgICByZXR1cm4gKCQuaXNGdW5jdGlvbihkKSkgPyBkKCkgOiBkO1xuICAgIH07XG5cbiAgICB2YXIgY29ubmVjdCA9IGZ1bmN0aW9uIChtZXRob2QsIHBhcmFtcywgY29ubmVjdE9wdGlvbnMpIHtcbiAgICAgICAgcGFyYW1zID0gcmVzdWx0KHBhcmFtcyk7XG4gICAgICAgIHBhcmFtcyA9ICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSB8fCAkLmlzQXJyYXkocGFyYW1zKSkgPyBKU09OLnN0cmluZ2lmeShwYXJhbXMpIDogcGFyYW1zO1xuXG4gICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRyYW5zcG9ydE9wdGlvbnMsIGNvbm5lY3RPcHRpb25zLCB7XG4gICAgICAgICAgICB0eXBlOiBtZXRob2QsXG4gICAgICAgICAgICBkYXRhOiBwYXJhbXNcbiAgICAgICAgfSk7XG4gICAgICAgIHZhciBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUyA9IFsnZGF0YScsICd1cmwnXTtcbiAgICAgICAgJC5lYWNoKG9wdGlvbnMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAoJC5pc0Z1bmN0aW9uKHZhbHVlKSAmJiAkLmluQXJyYXkoa2V5LCBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9uc1trZXldID0gdmFsdWUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKG9wdGlvbnMubG9nTGV2ZWwgJiYgb3B0aW9ucy5sb2dMZXZlbCA9PT0gJ0RFQlVHJykge1xuICAgICAgICAgICAgY29uc29sZS5sb2cob3B0aW9ucy51cmwpO1xuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3NGbiA9IG9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UsIGFqYXhTdGF0dXMsIGFqYXhSZXEpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgb2xkU3VjY2Vzc0ZuLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGJlZm9yZVNlbmQgPSBvcHRpb25zLmJlZm9yZVNlbmQ7XG4gICAgICAgIG9wdGlvbnMuYmVmb3JlU2VuZCA9IGZ1bmN0aW9uICh4aHIsIHNldHRpbmdzKSB7XG4gICAgICAgICAgICB4aHIucmVxdWVzdFVybCA9IChjb25uZWN0T3B0aW9ucyB8fCB7fSkudXJsO1xuICAgICAgICAgICAgaWYgKGJlZm9yZVNlbmQpIHtcbiAgICAgICAgICAgICAgICBiZWZvcmVTZW5kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuICQuYWpheChvcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgZ2V0OmZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdHRVQnLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuICAgICAgICBzcGxpdEdldDogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIH0sXG4gICAgICAgIHBvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncG9zdCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgcGF0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncGF0Y2gnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHB1dDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwdXQnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKHBhcmFtcywgYWpheE9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vREVMRVRFIGRvZXNuJ3Qgc3VwcG9ydCBib2R5IHBhcmFtcywgYnV0IGpRdWVyeSB0aGlua3MgaXQgZG9lcy5cbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRyYW5zcG9ydE9wdGlvbnMsIGFqYXhPcHRpb25zKTtcbiAgICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1ldGVyUGFyc2VyKHJlc3VsdChwYXJhbXMpKTtcbiAgICAgICAgICAgIGlmICgkLnRyaW0ocGFyYW1zKSkge1xuICAgICAgICAgICAgICAgIHZhciBkZWxpbWl0ZXIgPSAocmVzdWx0KG9wdGlvbnMudXJsKS5pbmRleE9mKCc/JykgPT09IC0xKSA/ICc/JyA6ICcmJztcbiAgICAgICAgICAgICAgICBvcHRpb25zLnVybCA9IHJlc3VsdChvcHRpb25zLnVybCkgKyBkZWxpbWl0ZXIgKyBwYXJhbXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdERUxFVEUnLCBudWxsLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgaGVhZDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydoZWFkJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBvcHRpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ29wdGlvbnMnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHRyYW5zcG9ydCA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9ub2RlLWh0dHAtdHJhbnNwb3J0JykgOiByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbnZhciB0cmFuc3BvcnQgPSByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbm1vZHVsZS5leHBvcnRzID0gdHJhbnNwb3J0O1xuIiwiLyoqXG4vKiBJbmhlcml0IGZyb20gYSBjbGFzcyAodXNpbmcgcHJvdG90eXBlIGJvcnJvd2luZylcbiovXG4ndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIGluaGVyaXQoQywgUCkge1xuICAgIHZhciBGID0gZnVuY3Rpb24gKCkge307XG4gICAgRi5wcm90b3R5cGUgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZSA9IG5ldyBGKCk7XG4gICAgQy5fX3N1cGVyID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDO1xufVxuXG4vKipcbiogU2hhbGxvdyBjb3B5IG9mIGFuIG9iamVjdFxuKi9cbnZhciBleHRlbmQgPSBmdW5jdGlvbiAoZGVzdCAvKiwgdmFyX2FyZ3MqLykge1xuICAgIHZhciBvYmogPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHZhciBjdXJyZW50O1xuICAgIGZvciAodmFyIGogPSAwOyBqPG9iai5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAoIShjdXJyZW50ID0gb2JqW2pdKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkbyBub3Qgd3JhcCBpbm5lciBpbiBkZXN0Lmhhc093blByb3BlcnR5IG9yIGJhZCB0aGluZ3Mgd2lsbCBoYXBwZW5cbiAgICAgICAgLypqc2hpbnQgLVcwODkgKi9cbiAgICAgICAgZm9yICh2YXIga2V5IGluIGN1cnJlbnQpIHtcbiAgICAgICAgICAgIGRlc3Rba2V5XSA9IGN1cnJlbnRba2V5XTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkZXN0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYmFzZSwgcHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgdmFyIHBhcmVudCA9IGJhc2U7XG4gICAgdmFyIGNoaWxkO1xuXG4gICAgY2hpbGQgPSBwcm9wcyAmJiBwcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSA/IHByb3BzLmNvbnN0cnVjdG9yIDogZnVuY3Rpb24gKCkgeyByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IH07XG5cbiAgICAvLyBhZGQgc3RhdGljIHByb3BlcnRpZXMgdG8gdGhlIGNoaWxkIGNvbnN0cnVjdG9yIGZ1bmN0aW9uXG4gICAgZXh0ZW5kKGNoaWxkLCBwYXJlbnQsIHN0YXRpY1Byb3BzKTtcblxuICAgIC8vIGFzc29jaWF0ZSBwcm90b3R5cGUgY2hhaW5cbiAgICBpbmhlcml0KGNoaWxkLCBwYXJlbnQpO1xuXG4gICAgLy8gYWRkIGluc3RhbmNlIHByb3BlcnRpZXNcbiAgICBpZiAocHJvcHMpIHtcbiAgICAgICAgZXh0ZW5kKGNoaWxkLnByb3RvdHlwZSwgcHJvcHMpO1xuICAgIH1cblxuICAgIC8vIGRvbmVcbiAgICByZXR1cm4gY2hpbGQ7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLypqc2hpbnQgbG9vcGZ1bmM6ZmFsc2UgKi9cblxuZnVuY3Rpb24gX3codmFsKSB7XG4gICAgaWYgKHZhbCAmJiB2YWwudGhlbikge1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgIH1cbiAgICB2YXIgcCA9ICQuRGVmZXJyZWQoKTtcbiAgICBwLnJlc29sdmUodmFsKTtcblxuICAgIHJldHVybiBwLnByb21pc2UoKTtcbn1cblxuZnVuY3Rpb24gc2VxKCkge1xuICAgIHZhciBsaXN0ID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmFwcGx5KGFyZ3VtZW50cyk7XG5cbiAgICBmdW5jdGlvbiBuZXh0KHApIHtcbiAgICAgICAgdmFyIGN1ciA9IGxpc3Quc3BsaWNlKDAsMSlbMF07XG5cbiAgICAgICAgaWYgKCFjdXIpIHtcbiAgICAgICAgICAgIHJldHVybiBwO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF93KGN1cihwKSkudGhlbihuZXh0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gKHNlZWQpIHtcbiAgICAgICAgcmV0dXJuIG5leHQoc2VlZCkuZmFpbChzZXEuZmFpbCk7XG4gICAgfTtcbn1cblxuZnVuY3Rpb24gTWFrZVNlcShvYmopIHtcbiAgICB2YXIgcmVzID0ge1xuICAgICAgICBfX2NhbGxzOiBbXSxcblxuICAgICAgICBvcmlnaW5hbDogb2JqLFxuXG4gICAgICAgIHRoZW46IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goZm4pO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIC8vIGNsZWFuIHVwXG4gICAgICAgICAgICB0aGlzLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIF90aGlzLl9fY2FsbHMubGVuZ3RoID0gMDtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBzZXEuYXBwbHkobnVsbCwgdGhpcy5fX2NhbGxzKSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGZhaWw6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgc2VxLmZhaWwgPSBmbjtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBmdW5jTWFrZXIgPSBmdW5jdGlvbiAocCwgb2JqKSB7XG4gICAgICAgIHZhciBmbiA9IG9ialtwXS5iaW5kKG9iaik7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goRnVuY3Rpb24uYmluZC5hcHBseShmbiwgW251bGxdLmNvbmNhdChhcmdzKSkpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH07XG4gICAgfTtcblxuICAgIGZvciAodmFyIHByb3AgaW4gb2JqKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygb2JqW3Byb3BdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXNbcHJvcF0gPSBmdW5jTWFrZXIocHJvcCwgb2JqKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlc1twcm9wXSA9IG9ialtwcm9wXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gTWFrZVNlcTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgX3BpY2s6IGZ1bmN0aW9uIChvYmosIHByb3BzKSB7XG4gICAgICAgIHZhciByZXMgPSB7fTtcbiAgICAgICAgZm9yICh2YXIgcCBpbiBvYmopIHtcbiAgICAgICAgICAgIGlmIChwcm9wcy5pbmRleE9mKHApICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIHJlc1twXSA9IG9ialtwXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxufTtcbiIsIi8qKlxuICogVXRpbGl0aWVzIGZvciB3b3JraW5nIHdpdGggcXVlcnkgc3RyaW5nc1xuKi9cbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSAoZnVuY3Rpb24gKCkge1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHRvIG1hdHJpeCBmb3JtYXRcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBxcyBPYmplY3QgdG8gY29udmVydCB0byBxdWVyeSBzdHJpbmdcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ30gICAgTWF0cml4LWZvcm1hdCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuICAgICAgICB0b01hdHJpeEZvcm1hdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCB8fCBxcyA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJzsnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgdmFyIE9QRVJBVE9SUyA9IFsnPCcsICc+JywgJyEnXTtcbiAgICAgICAgICAgICQuZWFjaChxcywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnc3RyaW5nJyB8fCAkLmluQXJyYXkoJC50cmltKHZhbHVlKS5jaGFyQXQoMCksIE9QRVJBVE9SUykgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gJz0nICsgdmFsdWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciBtdHJ4ID0gJzsnICsgcmV0dXJuQXJyYXkuam9pbignOycpO1xuICAgICAgICAgICAgcmV0dXJuIG10cng7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHN0cmluZ3MvYXJyYXlzL29iamVjdHMgdG8gdHlwZSAnYT1iJmI9YydcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b1F1ZXJ5Rm9ybWF0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgJC5lYWNoKHFzLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmICgkLmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUuam9pbignLCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICAvL01vc3RseSBmb3IgZGF0YSBhcGlcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBKU09OLnN0cmluZ2lmeSh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgJz0nICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciByZXN1bHQgPSByZXR1cm5BcnJheS5qb2luKCcmJyk7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyBzdHJpbmdzIG9mIHR5cGUgJ2E9YiZiPWMnIHRvIHsgYTpiLCBiOmN9XG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHFzXG4gICAgICAgICAqIEByZXR1cm4ge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHFzVG9PYmplY3Q6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQgfHwgcXMgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcXNBcnJheSA9IHFzLnNwbGl0KCcmJyk7XG4gICAgICAgICAgICB2YXIgcmV0dXJuT2JqID0ge307XG4gICAgICAgICAgICAkLmVhY2gocXNBcnJheSwgZnVuY3Rpb24gKGluZGV4LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBxS2V5ID0gdmFsdWUuc3BsaXQoJz0nKVswXTtcbiAgICAgICAgICAgICAgICB2YXIgcVZhbCA9IHZhbHVlLnNwbGl0KCc9JylbMV07XG5cbiAgICAgICAgICAgICAgICBpZiAocVZhbC5pbmRleE9mKCcsJykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHFWYWwgPSBxVmFsLnNwbGl0KCcsJyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuT2JqW3FLZXldID0gcVZhbDtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuT2JqO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOb3JtYWxpemVzIGFuZCBtZXJnZXMgc3RyaW5ncyBvZiB0eXBlICdhPWInLCB7IGI6Y30gdG8geyBhOmIsIGI6Y31cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzMVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXMyXG4gICAgICAgICAqIEByZXR1cm4ge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIG1lcmdlUVM6IGZ1bmN0aW9uIChxczEsIHFzMikge1xuICAgICAgICAgICAgdmFyIG9iajEgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMSkpO1xuICAgICAgICAgICAgdmFyIG9iajIgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMikpO1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHt9LCBvYmoxLCBvYmoyKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhZGRUcmFpbGluZ1NsYXNoOiBmdW5jdGlvbiAodXJsKSB7XG4gICAgICAgICAgICBpZiAoIXVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAodXJsLmNoYXJBdCh1cmwubGVuZ3RoIC0gMSkgPT09ICcvJykgPyB1cmwgOiAodXJsICsgJy8nKTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuXG5cblxuIiwiLyoqXG4gKiBVdGlsaXRpZXMgZm9yIHdvcmtpbmcgd2l0aCB0aGUgcnVuIHNlcnZpY2VcbiovXG4ndXNlIHN0cmljdCc7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuL3F1ZXJ5LXV0aWwnKTtcbnZhciBNQVhfVVJMX0xFTkdUSCA9IDIwNDg7XG5cbm1vZHVsZS5leHBvcnRzID0gKGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICAvKipcbiAgICAgICAgICogcmV0dXJucyBvcGVyYXRpb25zIG9mIHRoZSBmb3JtIGBbW29wMSxvcDJdLCBbYXJnMSwgYXJnMl1dYFxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R8QXJyYXl8U3RyaW5nfSBgb3BlcmF0aW9uc2Agb3BlcmF0aW9ucyB0byBwZXJmb3JtXG4gICAgICAgICAqIEBwYXJhbSAge0FycmF5fSBgYXJnc2AgYXJndW1lbnRzIGZvciBvcGVyYXRpb25cbiAgICAgICAgICogQHJldHVybiB7U3RyaW5nfSAgICBNYXRyaXgtZm9ybWF0IHF1ZXJ5IHBhcmFtZXRlcnNcbiAgICAgICAgICovXG4gICAgICAgIG5vcm1hbGl6ZU9wZXJhdGlvbnM6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBhcmdzKSB7XG4gICAgICAgICAgICBpZiAoIWFyZ3MpIHtcbiAgICAgICAgICAgICAgICBhcmdzID0gW107XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgcmV0dXJuTGlzdCA9IHtcbiAgICAgICAgICAgICAgICBvcHM6IFtdLFxuICAgICAgICAgICAgICAgIGFyZ3M6IFtdXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX2NvbmNhdCA9IGZ1bmN0aW9uIChhcnIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKGFyciAhPT0gbnVsbCAmJiBhcnIgIT09IHVuZGVmaW5lZCkgPyBbXS5jb25jYXQoYXJyKSA6IFtdO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgLy97IGFkZDogWzEsMl0sIHN1YnRyYWN0OiBbMiw0XSB9XG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZVBsYWluT2JqZWN0cyA9IGZ1bmN0aW9uIChvcGVyYXRpb25zLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICQuZWFjaChvcGVyYXRpb25zLCBmdW5jdGlvbiAob3BuLCBhcmcpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcG4pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KGFyZykpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIC8veyBuYW1lOiAnYWRkJywgcGFyYW1zOiBbMV0gfVxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVTdHJ1Y3R1cmVkT2JqZWN0cyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcGVyYXRpb24ubmFtZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChvcGVyYXRpb24ucGFyYW1zKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZU9iamVjdCA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKChvcGVyYXRpb24ubmFtZSkgPyBfbm9ybWFsaXplU3RydWN0dXJlZE9iamVjdHMgOiBfbm9ybWFsaXplUGxhaW5PYmplY3RzKShvcGVyYXRpb24sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVMaXRlcmFscyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIGFyZ3MsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcGVyYXRpb24pO1xuICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQoYXJncykpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZUFycmF5cyA9IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBhcmcsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJC5lYWNoKG9wZXJhdGlvbnMsIGZ1bmN0aW9uIChpbmRleCwgb3BuKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qob3BuKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgX25vcm1hbGl6ZU9iamVjdChvcG4sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgX25vcm1hbGl6ZUxpdGVyYWxzKG9wbiwgYXJnc1tpbmRleF0sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KG9wZXJhdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZU9iamVjdChvcGVyYXRpb25zLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoJC5pc0FycmF5KG9wZXJhdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZUFycmF5cyhvcGVyYXRpb25zLCBhcmdzLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZUxpdGVyYWxzKG9wZXJhdGlvbnMsIGFyZ3MsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgfSxcblxuICAgICAgICBzcGxpdEdldEZhY3Rvcnk6IGZ1bmN0aW9uIChodHRwT3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICB2YXIgaHR0cCA9IHRoaXM7XG4gICAgICAgICAgICAgICAgdmFyIGdldFZhbHVlID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhbHVlID0gb3B0aW9uc1tuYW1lXSB8fCBodHRwT3B0aW9uc1tuYW1lXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciBnZXRGaW5hbFVybCA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybCA9IGdldFZhbHVlKCd1cmwnLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRhdGEgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZXJlIGlzIGVhc3kgKG9yIGtub3duKSB3YXkgdG8gZ2V0IHRoZSBmaW5hbCBVUkwganF1ZXJ5IGlzIGdvaW5nIHRvIHNlbmQgc29cbiAgICAgICAgICAgICAgICAgICAgLy8gd2UncmUgcmVwbGljYXRpbmcgaXQuIFRoZSBwcm9jZXNzIG1pZ2h0IGNoYW5nZSBhdCBzb21lIHBvaW50IGJ1dCBpdCBwcm9iYWJseSB3aWxsIG5vdC5cbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gUmVtb3ZlIGhhc2hcbiAgICAgICAgICAgICAgICAgICAgdXJsID0gdXJsLnJlcGxhY2UoLyMuKiQvLCAnJyk7XG4gICAgICAgICAgICAgICAgICAgIC8vIDEuIEFwcGVuZCBxdWVyeSBzdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXJ5UGFyYW1zID0gcXV0aWwudG9RdWVyeUZvcm1hdChkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXN0aW9uSWR4ID0gdXJsLmluZGV4T2YoJz8nKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHF1ZXJ5UGFyYW1zICYmIHF1ZXN0aW9uSWR4ID4gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmwgKyAnJicgKyBxdWVyeVBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChxdWVyeVBhcmFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybCArICc/JyArIHF1ZXJ5UGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmw7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgdXJsID0gZ2V0RmluYWxVcmwocGFyYW1zKTtcbiAgICAgICAgICAgICAgICAvLyBXZSBtdXN0IHNwbGl0IHRoZSBHRVQgaW4gbXVsdGlwbGUgc2hvcnQgVVJMJ3NcbiAgICAgICAgICAgICAgICAvLyBUaGUgb25seSBwcm9wZXJ0eSBhbGxvd2VkIHRvIGJlIHNwbGl0IGlzIFwiaW5jbHVkZVwiXG4gICAgICAgICAgICAgICAgaWYgKHBhcmFtcyAmJiBwYXJhbXMuaW5jbHVkZSAmJiB1cmwubGVuZ3RoID4gTUFYX1VSTF9MRU5HVEgpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmFtc0NvcHkgPSAkLmV4dGVuZCh0cnVlLCB7fSwgcGFyYW1zKTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHBhcmFtc0NvcHkuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybE5vSW5jbHVkZXMgPSBnZXRGaW5hbFVybChwYXJhbXNDb3B5KTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRpZmYgPSBNQVhfVVJMX0xFTkdUSCAtIHVybE5vSW5jbHVkZXMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IG9wdGlvbnMuc3VjY2VzcyB8fCBodHRwT3B0aW9ucy5zdWNjZXNzIHx8ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZEVycm9yID0gb3B0aW9ucy5lcnJvciB8fCBodHRwT3B0aW9ucy5lcnJvciB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSB0aGUgb3JpZ2luYWwgc3VjY2VzcyBhbmQgZXJyb3IgY2FsbGJhY2tzXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuc3VjY2VzcyA9ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvciA9ICQubm9vcDtcblxuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZSA9IHBhcmFtcy5pbmNsdWRlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VyckluY2x1ZGVzID0gW107XG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmNsdWRlT3B0cyA9IFtjdXJySW5jbHVkZXNdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHZhcmlhYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgYSBncmVlZHkgYXBwcm9hY2ggZm9yIG5vdywgY2FuIGJlIG9wdGltaXplZCB0byBiZSBzb2x2ZWQgaW4gYSBtb3JlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBlZmZpY2llbnQgd2F5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyArIDEgaXMgdGhlIGNvbW1hXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3Vyckxlbmd0aCArIHZhcmlhYmxlLmxlbmd0aCArIDEgPCBkaWZmKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzLnB1c2godmFyaWFibGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJMZW5ndGggKz0gdmFyaWFibGUubGVuZ3RoICsgMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzID0gW3ZhcmlhYmxlXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlT3B0cy5wdXNoKGN1cnJJbmNsdWRlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aCArIHZhcmlhYmxlLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB2YXIgcmVxcyA9ICQubWFwKGluY2x1ZGVPcHRzLCBmdW5jdGlvbiAoaW5jbHVkZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlcVBhcmFtcyA9ICQuZXh0ZW5kKHt9LCBwYXJhbXMsIHsgaW5jbHVkZTogaW5jbHVkZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChyZXFQYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgJC53aGVuLmFwcGx5KCQsIHJlcXMpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRWFjaCBhcmd1bWVudCBhcmUgYXJyYXlzIG9mIHRoZSBhcmd1bWVudHMgb2YgZWFjaCBkb25lIHJlcXVlc3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgZmlyc3QgYXJyYXkgb2YgYXJndW1lbnRzIGlzIHRoZSBkYXRhXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNWYWxpZCA9IGFyZ3VtZW50c1swXSAmJiBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaG91bGQgbmV2ZXIgaGFwcGVuLi4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpcnN0UmVzcG9uc2UgPSBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNSdW5BUEkgPSAoaXNPYmplY3QgJiYgJC5pc1BsYWluT2JqZWN0KGZpcnN0UmVzcG9uc2UudmFyaWFibGVzKSkgfHwgIWlzT2JqZWN0O1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzUnVuQVBJKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzT2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnZ3JlZ2F0ZSB0aGUgdmFyaWFibGVzIHByb3BlcnR5IG9ubHlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZVJ1biA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJ1biA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVSdW4udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZVJ1biwgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFycmF5IG9mIHJ1bnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWdyZWdhdGUgdmFyaWFibGVzIGluIGVhY2ggcnVuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkUnVucyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVucyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISQuaXNBcnJheShydW5zKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChydW5zLCBmdW5jdGlvbiAoaWR4UnVuLCBydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocnVuLmlkICYmICFhZ2dyZWdhdGVkUnVuc1tydW4uaWRdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bi52YXJpYWJsZXMgPSBydW4udmFyaWFibGVzIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVuc1tydW4uaWRdID0gcnVuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocnVuLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHR1cm4gaXQgaW50byBhbiBhcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVucyA9ICQubWFwKGFnZ3JlZ2F0ZWRSdW5zLCBmdW5jdGlvbiAocnVuKSB7IHJldHVybiBydW47IH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyB2YXJpYWJsZXMgQVBJXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSByZXNwb25zZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkVmFyaWFibGVzID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFycyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIHZhcnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IuYXBwbHkoaHR0cCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZWplY3QuYXBwbHkoZHRkLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuIl19 +//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL25vZGVfbW9kdWxlcy9pZWVlNzU0L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvaXMtYXJyYXkvaW5kZXguanMiLCJzcmMvYXBpLXZlcnNpb24uanNvbiIsInNyYy9hcHAuanMiLCJzcmMvbWFuYWdlcnMvYXV0aC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2NoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2tleS1uYW1lcy5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9hbHdheXMtbmV3LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2lkZW50aXR5LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL211bHRpcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcC5qcyIsInNyYy9tYW5hZ2Vycy9zY2VuYXJpby1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3NwZWNpYWwtb3BlcmF0aW9ucy5qcyIsInNyYy9tYW5hZ2Vycy93b3JsZC1tYW5hZ2VyLmpzIiwic3JjL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyLmpzIiwic3JjL3N0b3JlL2Nvb2tpZS1zdG9yZS5qcyIsInNyYy9zdG9yZS9zdG9yZS1mYWN0b3J5LmpzIiwic3JjL3RyYW5zcG9ydC9hamF4LWh0dHAtdHJhbnNwb3J0LmpzIiwic3JjL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5LmpzIiwic3JjL3V0aWwvaW5oZXJpdC5qcyIsInNyYy91dGlsL21ha2Utc2VxdWVuY2UuanMiLCJzcmMvdXRpbC9vYmplY3QtdXRpbC5qcyIsInNyYy91dGlsL3F1ZXJ5LXV0aWwuanMiLCJzcmMvdXRpbC9ydW4tdXRpbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN4Z0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNVdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6T0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdFFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4ZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6SkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM3VCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8qIVxuICogVGhlIGJ1ZmZlciBtb2R1bGUgZnJvbSBub2RlLmpzLCBmb3IgdGhlIGJyb3dzZXIuXG4gKlxuICogQGF1dGhvciAgIEZlcm9zcyBBYm91a2hhZGlqZWggPGZlcm9zc0BmZXJvc3Mub3JnPiA8aHR0cDovL2Zlcm9zcy5vcmc+XG4gKiBAbGljZW5zZSAgTUlUXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIG5vLXByb3RvICovXG5cbnZhciBiYXNlNjQgPSByZXF1aXJlKCdiYXNlNjQtanMnKVxudmFyIGllZWU3NTQgPSByZXF1aXJlKCdpZWVlNzU0JylcbnZhciBpc0FycmF5ID0gcmVxdWlyZSgnaXMtYXJyYXknKVxuXG5leHBvcnRzLkJ1ZmZlciA9IEJ1ZmZlclxuZXhwb3J0cy5TbG93QnVmZmVyID0gU2xvd0J1ZmZlclxuZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFUyA9IDUwXG5CdWZmZXIucG9vbFNpemUgPSA4MTkyIC8vIG5vdCB1c2VkIGJ5IHRoaXMgaW1wbGVtZW50YXRpb25cblxudmFyIHJvb3RQYXJlbnQgPSB7fVxuXG4vKipcbiAqIElmIGBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVGA6XG4gKiAgID09PSB0cnVlICAgIFVzZSBVaW50OEFycmF5IGltcGxlbWVudGF0aW9uIChmYXN0ZXN0KVxuICogICA9PT0gZmFsc2UgICBVc2UgT2JqZWN0IGltcGxlbWVudGF0aW9uIChtb3N0IGNvbXBhdGlibGUsIGV2ZW4gSUU2KVxuICpcbiAqIEJyb3dzZXJzIHRoYXQgc3VwcG9ydCB0eXBlZCBhcnJheXMgYXJlIElFIDEwKywgRmlyZWZveCA0KywgQ2hyb21lIDcrLCBTYWZhcmkgNS4xKyxcbiAqIE9wZXJhIDExLjYrLCBpT1MgNC4yKy5cbiAqXG4gKiBEdWUgdG8gdmFyaW91cyBicm93c2VyIGJ1Z3MsIHNvbWV0aW1lcyB0aGUgT2JqZWN0IGltcGxlbWVudGF0aW9uIHdpbGwgYmUgdXNlZCBldmVuXG4gKiB3aGVuIHRoZSBicm93c2VyIHN1cHBvcnRzIHR5cGVkIGFycmF5cy5cbiAqXG4gKiBOb3RlOlxuICpcbiAqICAgLSBGaXJlZm94IDQtMjkgbGFja3Mgc3VwcG9ydCBmb3IgYWRkaW5nIG5ldyBwcm9wZXJ0aWVzIHRvIGBVaW50OEFycmF5YCBpbnN0YW5jZXMsXG4gKiAgICAgU2VlOiBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD02OTU0MzguXG4gKlxuICogICAtIFNhZmFyaSA1LTcgbGFja3Mgc3VwcG9ydCBmb3IgY2hhbmdpbmcgdGhlIGBPYmplY3QucHJvdG90eXBlLmNvbnN0cnVjdG9yYCBwcm9wZXJ0eVxuICogICAgIG9uIG9iamVjdHMuXG4gKlxuICogICAtIENocm9tZSA5LTEwIGlzIG1pc3NpbmcgdGhlIGBUeXBlZEFycmF5LnByb3RvdHlwZS5zdWJhcnJheWAgZnVuY3Rpb24uXG4gKlxuICogICAtIElFMTAgaGFzIGEgYnJva2VuIGBUeXBlZEFycmF5LnByb3RvdHlwZS5zdWJhcnJheWAgZnVuY3Rpb24gd2hpY2ggcmV0dXJucyBhcnJheXMgb2ZcbiAqICAgICBpbmNvcnJlY3QgbGVuZ3RoIGluIHNvbWUgc2l0dWF0aW9ucy5cblxuICogV2UgZGV0ZWN0IHRoZXNlIGJ1Z2d5IGJyb3dzZXJzIGFuZCBzZXQgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYCB0byBgZmFsc2VgIHNvIHRoZXlcbiAqIGdldCB0aGUgT2JqZWN0IGltcGxlbWVudGF0aW9uLCB3aGljaCBpcyBzbG93ZXIgYnV0IGJlaGF2ZXMgY29ycmVjdGx5LlxuICovXG5CdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCA9IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUICE9PSB1bmRlZmluZWRcbiAgPyBnbG9iYWwuVFlQRURfQVJSQVlfU1VQUE9SVFxuICA6IHR5cGVkQXJyYXlTdXBwb3J0KClcblxuZnVuY3Rpb24gdHlwZWRBcnJheVN1cHBvcnQgKCkge1xuICBmdW5jdGlvbiBCYXIgKCkge31cbiAgdHJ5IHtcbiAgICB2YXIgYXJyID0gbmV3IFVpbnQ4QXJyYXkoMSlcbiAgICBhcnIuZm9vID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gNDIgfVxuICAgIGFyci5jb25zdHJ1Y3RvciA9IEJhclxuICAgIHJldHVybiBhcnIuZm9vKCkgPT09IDQyICYmIC8vIHR5cGVkIGFycmF5IGluc3RhbmNlcyBjYW4gYmUgYXVnbWVudGVkXG4gICAgICAgIGFyci5jb25zdHJ1Y3RvciA9PT0gQmFyICYmIC8vIGNvbnN0cnVjdG9yIGNhbiBiZSBzZXRcbiAgICAgICAgdHlwZW9mIGFyci5zdWJhcnJheSA9PT0gJ2Z1bmN0aW9uJyAmJiAvLyBjaHJvbWUgOS0xMCBsYWNrIGBzdWJhcnJheWBcbiAgICAgICAgYXJyLnN1YmFycmF5KDEsIDEpLmJ5dGVMZW5ndGggPT09IDAgLy8gaWUxMCBoYXMgYnJva2VuIGBzdWJhcnJheWBcbiAgfSBjYXRjaCAoZSkge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbmZ1bmN0aW9uIGtNYXhMZW5ndGggKCkge1xuICByZXR1cm4gQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRcbiAgICA/IDB4N2ZmZmZmZmZcbiAgICA6IDB4M2ZmZmZmZmZcbn1cblxuLyoqXG4gKiBDbGFzczogQnVmZmVyXG4gKiA9PT09PT09PT09PT09XG4gKlxuICogVGhlIEJ1ZmZlciBjb25zdHJ1Y3RvciByZXR1cm5zIGluc3RhbmNlcyBvZiBgVWludDhBcnJheWAgdGhhdCBhcmUgYXVnbWVudGVkXG4gKiB3aXRoIGZ1bmN0aW9uIHByb3BlcnRpZXMgZm9yIGFsbCB0aGUgbm9kZSBgQnVmZmVyYCBBUEkgZnVuY3Rpb25zLiBXZSB1c2VcbiAqIGBVaW50OEFycmF5YCBzbyB0aGF0IHNxdWFyZSBicmFja2V0IG5vdGF0aW9uIHdvcmtzIGFzIGV4cGVjdGVkIC0tIGl0IHJldHVybnNcbiAqIGEgc2luZ2xlIG9jdGV0LlxuICpcbiAqIEJ5IGF1Z21lbnRpbmcgdGhlIGluc3RhbmNlcywgd2UgY2FuIGF2b2lkIG1vZGlmeWluZyB0aGUgYFVpbnQ4QXJyYXlgXG4gKiBwcm90b3R5cGUuXG4gKi9cbmZ1bmN0aW9uIEJ1ZmZlciAoYXJnKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBCdWZmZXIpKSB7XG4gICAgLy8gQXZvaWQgZ29pbmcgdGhyb3VnaCBhbiBBcmd1bWVudHNBZGFwdG9yVHJhbXBvbGluZSBpbiB0aGUgY29tbW9uIGNhc2UuXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSByZXR1cm4gbmV3IEJ1ZmZlcihhcmcsIGFyZ3VtZW50c1sxXSlcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcihhcmcpXG4gIH1cblxuICB0aGlzLmxlbmd0aCA9IDBcbiAgdGhpcy5wYXJlbnQgPSB1bmRlZmluZWRcblxuICAvLyBDb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdudW1iZXInKSB7XG4gICAgcmV0dXJuIGZyb21OdW1iZXIodGhpcywgYXJnKVxuICB9XG5cbiAgLy8gU2xpZ2h0bHkgbGVzcyBjb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIGZyb21TdHJpbmcodGhpcywgYXJnLCBhcmd1bWVudHMubGVuZ3RoID4gMSA/IGFyZ3VtZW50c1sxXSA6ICd1dGY4JylcbiAgfVxuXG4gIC8vIFVudXN1YWwuXG4gIHJldHVybiBmcm9tT2JqZWN0KHRoaXMsIGFyZylcbn1cblxuZnVuY3Rpb24gZnJvbU51bWJlciAodGhhdCwgbGVuZ3RoKSB7XG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGggPCAwID8gMCA6IGNoZWNrZWQobGVuZ3RoKSB8IDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICB0aGF0W2ldID0gMFxuICAgIH1cbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tU3RyaW5nICh0aGF0LCBzdHJpbmcsIGVuY29kaW5nKSB7XG4gIGlmICh0eXBlb2YgZW5jb2RpbmcgIT09ICdzdHJpbmcnIHx8IGVuY29kaW5nID09PSAnJykgZW5jb2RpbmcgPSAndXRmOCdcblxuICAvLyBBc3N1bXB0aW9uOiBieXRlTGVuZ3RoKCkgcmV0dXJuIHZhbHVlIGlzIGFsd2F5cyA8IGtNYXhMZW5ndGguXG4gIHZhciBsZW5ndGggPSBieXRlTGVuZ3RoKHN0cmluZywgZW5jb2RpbmcpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuXG4gIHRoYXQud3JpdGUoc3RyaW5nLCBlbmNvZGluZylcbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbU9iamVjdCAodGhhdCwgb2JqZWN0KSB7XG4gIGlmIChCdWZmZXIuaXNCdWZmZXIob2JqZWN0KSkgcmV0dXJuIGZyb21CdWZmZXIodGhhdCwgb2JqZWN0KVxuXG4gIGlmIChpc0FycmF5KG9iamVjdCkpIHJldHVybiBmcm9tQXJyYXkodGhhdCwgb2JqZWN0KVxuXG4gIGlmIChvYmplY3QgPT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ211c3Qgc3RhcnQgd2l0aCBudW1iZXIsIGJ1ZmZlciwgYXJyYXkgb3Igc3RyaW5nJylcbiAgfVxuXG4gIGlmICh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgaWYgKG9iamVjdC5idWZmZXIgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikge1xuICAgICAgcmV0dXJuIGZyb21UeXBlZEFycmF5KHRoYXQsIG9iamVjdClcbiAgICB9XG4gICAgaWYgKG9iamVjdCBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgICByZXR1cm4gZnJvbUFycmF5QnVmZmVyKHRoYXQsIG9iamVjdClcbiAgICB9XG4gIH1cblxuICBpZiAob2JqZWN0Lmxlbmd0aCkgcmV0dXJuIGZyb21BcnJheUxpa2UodGhhdCwgb2JqZWN0KVxuXG4gIHJldHVybiBmcm9tSnNvbk9iamVjdCh0aGF0LCBvYmplY3QpXG59XG5cbmZ1bmN0aW9uIGZyb21CdWZmZXIgKHRoYXQsIGJ1ZmZlcikge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChidWZmZXIubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcbiAgYnVmZmVyLmNvcHkodGhhdCwgMCwgMCwgbGVuZ3RoKVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXkgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vLyBEdXBsaWNhdGUgb2YgZnJvbUFycmF5KCkgdG8ga2VlcCBmcm9tQXJyYXkoKSBtb25vbW9ycGhpYy5cbmZ1bmN0aW9uIGZyb21UeXBlZEFycmF5ICh0aGF0LCBhcnJheSkge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICAvLyBUcnVuY2F0aW5nIHRoZSBlbGVtZW50cyBpcyBwcm9iYWJseSBub3Qgd2hhdCBwZW9wbGUgZXhwZWN0IGZyb20gdHlwZWRcbiAgLy8gYXJyYXlzIHdpdGggQllURVNfUEVSX0VMRU1FTlQgPiAxIGJ1dCBpdCdzIGNvbXBhdGlibGUgd2l0aCB0aGUgYmVoYXZpb3JcbiAgLy8gb2YgdGhlIG9sZCBCdWZmZXIgY29uc3RydWN0b3IuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlCdWZmZXIgKHRoYXQsIGFycmF5KSB7XG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIFJldHVybiBhbiBhdWdtZW50ZWQgYFVpbnQ4QXJyYXlgIGluc3RhbmNlLCBmb3IgYmVzdCBwZXJmb3JtYW5jZVxuICAgIGFycmF5LmJ5dGVMZW5ndGhcbiAgICB0aGF0ID0gQnVmZmVyLl9hdWdtZW50KG5ldyBVaW50OEFycmF5KGFycmF5KSlcbiAgfSBlbHNlIHtcbiAgICAvLyBGYWxsYmFjazogUmV0dXJuIGFuIG9iamVjdCBpbnN0YW5jZSBvZiB0aGUgQnVmZmVyIGNsYXNzXG4gICAgdGhhdCA9IGZyb21UeXBlZEFycmF5KHRoYXQsIG5ldyBVaW50OEFycmF5KGFycmF5KSlcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlMaWtlICh0aGF0LCBhcnJheSkge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuLy8gRGVzZXJpYWxpemUgeyB0eXBlOiAnQnVmZmVyJywgZGF0YTogWzEsMiwzLC4uLl0gfSBpbnRvIGEgQnVmZmVyIG9iamVjdC5cbi8vIFJldHVybnMgYSB6ZXJvLWxlbmd0aCBidWZmZXIgZm9yIGlucHV0cyB0aGF0IGRvbid0IGNvbmZvcm0gdG8gdGhlIHNwZWMuXG5mdW5jdGlvbiBmcm9tSnNvbk9iamVjdCAodGhhdCwgb2JqZWN0KSB7XG4gIHZhciBhcnJheVxuICB2YXIgbGVuZ3RoID0gMFxuXG4gIGlmIChvYmplY3QudHlwZSA9PT0gJ0J1ZmZlcicgJiYgaXNBcnJheShvYmplY3QuZGF0YSkpIHtcbiAgICBhcnJheSA9IG9iamVjdC5kYXRhXG4gICAgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB9XG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICBCdWZmZXIucHJvdG90eXBlLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXkucHJvdG90eXBlXG4gIEJ1ZmZlci5fX3Byb3RvX18gPSBVaW50OEFycmF5XG59XG5cbmZ1bmN0aW9uIGFsbG9jYXRlICh0aGF0LCBsZW5ndGgpIHtcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgdGhhdCA9IEJ1ZmZlci5fYXVnbWVudChuZXcgVWludDhBcnJheShsZW5ndGgpKVxuICAgIHRoYXQuX19wcm90b19fID0gQnVmZmVyLnByb3RvdHlwZVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0Lmxlbmd0aCA9IGxlbmd0aFxuICAgIHRoYXQuX2lzQnVmZmVyID0gdHJ1ZVxuICB9XG5cbiAgdmFyIGZyb21Qb29sID0gbGVuZ3RoICE9PSAwICYmIGxlbmd0aCA8PSBCdWZmZXIucG9vbFNpemUgPj4+IDFcbiAgaWYgKGZyb21Qb29sKSB0aGF0LnBhcmVudCA9IHJvb3RQYXJlbnRcblxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBjaGVja2VkIChsZW5ndGgpIHtcbiAgLy8gTm90ZTogY2Fubm90IHVzZSBgbGVuZ3RoIDwga01heExlbmd0aGAgaGVyZSBiZWNhdXNlIHRoYXQgZmFpbHMgd2hlblxuICAvLyBsZW5ndGggaXMgTmFOICh3aGljaCBpcyBvdGhlcndpc2UgY29lcmNlZCB0byB6ZXJvLilcbiAgaWYgKGxlbmd0aCA+PSBrTWF4TGVuZ3RoKCkpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignQXR0ZW1wdCB0byBhbGxvY2F0ZSBCdWZmZXIgbGFyZ2VyIHRoYW4gbWF4aW11bSAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAnc2l6ZTogMHgnICsga01heExlbmd0aCgpLnRvU3RyaW5nKDE2KSArICcgYnl0ZXMnKVxuICB9XG4gIHJldHVybiBsZW5ndGggfCAwXG59XG5cbmZ1bmN0aW9uIFNsb3dCdWZmZXIgKHN1YmplY3QsIGVuY29kaW5nKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBTbG93QnVmZmVyKSkgcmV0dXJuIG5ldyBTbG93QnVmZmVyKHN1YmplY3QsIGVuY29kaW5nKVxuXG4gIHZhciBidWYgPSBuZXcgQnVmZmVyKHN1YmplY3QsIGVuY29kaW5nKVxuICBkZWxldGUgYnVmLnBhcmVudFxuICByZXR1cm4gYnVmXG59XG5cbkJ1ZmZlci5pc0J1ZmZlciA9IGZ1bmN0aW9uIGlzQnVmZmVyIChiKSB7XG4gIHJldHVybiAhIShiICE9IG51bGwgJiYgYi5faXNCdWZmZXIpXG59XG5cbkJ1ZmZlci5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYSwgYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihhKSB8fCAhQnVmZmVyLmlzQnVmZmVyKGIpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnRzIG11c3QgYmUgQnVmZmVycycpXG4gIH1cblxuICBpZiAoYSA9PT0gYikgcmV0dXJuIDBcblxuICB2YXIgeCA9IGEubGVuZ3RoXG4gIHZhciB5ID0gYi5sZW5ndGhcblxuICB2YXIgaSA9IDBcbiAgdmFyIGxlbiA9IE1hdGgubWluKHgsIHkpXG4gIHdoaWxlIChpIDwgbGVuKSB7XG4gICAgaWYgKGFbaV0gIT09IGJbaV0pIGJyZWFrXG5cbiAgICArK2lcbiAgfVxuXG4gIGlmIChpICE9PSBsZW4pIHtcbiAgICB4ID0gYVtpXVxuICAgIHkgPSBiW2ldXG4gIH1cblxuICBpZiAoeCA8IHkpIHJldHVybiAtMVxuICBpZiAoeSA8IHgpIHJldHVybiAxXG4gIHJldHVybiAwXG59XG5cbkJ1ZmZlci5pc0VuY29kaW5nID0gZnVuY3Rpb24gaXNFbmNvZGluZyAoZW5jb2RpbmcpIHtcbiAgc3dpdGNoIChTdHJpbmcoZW5jb2RpbmcpLnRvTG93ZXJDYXNlKCkpIHtcbiAgICBjYXNlICdoZXgnOlxuICAgIGNhc2UgJ3V0ZjgnOlxuICAgIGNhc2UgJ3V0Zi04JzpcbiAgICBjYXNlICdhc2NpaSc6XG4gICAgY2FzZSAnYmluYXJ5JzpcbiAgICBjYXNlICdiYXNlNjQnOlxuICAgIGNhc2UgJ3Jhdyc6XG4gICAgY2FzZSAndWNzMic6XG4gICAgY2FzZSAndWNzLTInOlxuICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgIHJldHVybiB0cnVlXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbkJ1ZmZlci5jb25jYXQgPSBmdW5jdGlvbiBjb25jYXQgKGxpc3QsIGxlbmd0aCkge1xuICBpZiAoIWlzQXJyYXkobGlzdCkpIHRocm93IG5ldyBUeXBlRXJyb3IoJ2xpc3QgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzLicpXG5cbiAgaWYgKGxpc3QubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIG5ldyBCdWZmZXIoMClcbiAgfVxuXG4gIHZhciBpXG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCkge1xuICAgIGxlbmd0aCA9IDBcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykge1xuICAgICAgbGVuZ3RoICs9IGxpc3RbaV0ubGVuZ3RoXG4gICAgfVxuICB9XG5cbiAgdmFyIGJ1ZiA9IG5ldyBCdWZmZXIobGVuZ3RoKVxuICB2YXIgcG9zID0gMFxuICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykge1xuICAgIHZhciBpdGVtID0gbGlzdFtpXVxuICAgIGl0ZW0uY29weShidWYsIHBvcylcbiAgICBwb3MgKz0gaXRlbS5sZW5ndGhcbiAgfVxuICByZXR1cm4gYnVmXG59XG5cbmZ1bmN0aW9uIGJ5dGVMZW5ndGggKHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBzdHJpbmcgIT09ICdzdHJpbmcnKSBzdHJpbmcgPSAnJyArIHN0cmluZ1xuXG4gIHZhciBsZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChsZW4gPT09IDApIHJldHVybiAwXG5cbiAgLy8gVXNlIGEgZm9yIGxvb3AgdG8gYXZvaWQgcmVjdXJzaW9uXG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG4gIGZvciAoOzspIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgLy8gRGVwcmVjYXRlZFxuICAgICAgY2FzZSAncmF3JzpcbiAgICAgIGNhc2UgJ3Jhd3MnOlxuICAgICAgICByZXR1cm4gbGVuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhUb0J5dGVzKHN0cmluZykubGVuZ3RoXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gbGVuICogMlxuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGxlbiA+Pj4gMVxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGhcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgcmV0dXJuIHV0ZjhUb0J5dGVzKHN0cmluZykubGVuZ3RoIC8vIGFzc3VtZSB1dGY4XG4gICAgICAgIGVuY29kaW5nID0gKCcnICsgZW5jb2RpbmcpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5CdWZmZXIuYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGhcblxuLy8gcHJlLXNldCBmb3IgdmFsdWVzIHRoYXQgbWF5IGV4aXN0IGluIHRoZSBmdXR1cmVcbkJ1ZmZlci5wcm90b3R5cGUubGVuZ3RoID0gdW5kZWZpbmVkXG5CdWZmZXIucHJvdG90eXBlLnBhcmVudCA9IHVuZGVmaW5lZFxuXG5mdW5jdGlvbiBzbG93VG9TdHJpbmcgKGVuY29kaW5nLCBzdGFydCwgZW5kKSB7XG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG5cbiAgc3RhcnQgPSBzdGFydCB8IDBcbiAgZW5kID0gZW5kID09PSB1bmRlZmluZWQgfHwgZW5kID09PSBJbmZpbml0eSA/IHRoaXMubGVuZ3RoIDogZW5kIHwgMFxuXG4gIGlmICghZW5jb2RpbmcpIGVuY29kaW5nID0gJ3V0ZjgnXG4gIGlmIChzdGFydCA8IDApIHN0YXJ0ID0gMFxuICBpZiAoZW5kID4gdGhpcy5sZW5ndGgpIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmIChlbmQgPD0gc3RhcnQpIHJldHVybiAnJ1xuXG4gIHdoaWxlICh0cnVlKSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGhleFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgICAgcmV0dXJuIGFzY2lpU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgICAgcmV0dXJuIGJpbmFyeVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIHJldHVybiBiYXNlNjRTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gdXRmMTZsZVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgICAgICBlbmNvZGluZyA9IChlbmNvZGluZyArICcnKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gdG9TdHJpbmcgKCkge1xuICB2YXIgbGVuZ3RoID0gdGhpcy5sZW5ndGggfCAwXG4gIGlmIChsZW5ndGggPT09IDApIHJldHVybiAnJ1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCAwLCBsZW5ndGgpXG4gIHJldHVybiBzbG93VG9TdHJpbmcuYXBwbHkodGhpcywgYXJndW1lbnRzKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uIGVxdWFscyAoYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpXG4gIGlmICh0aGlzID09PSBiKSByZXR1cm4gdHJ1ZVxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYikgPT09IDBcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbnNwZWN0ID0gZnVuY3Rpb24gaW5zcGVjdCAoKSB7XG4gIHZhciBzdHIgPSAnJ1xuICB2YXIgbWF4ID0gZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFU1xuICBpZiAodGhpcy5sZW5ndGggPiAwKSB7XG4gICAgc3RyID0gdGhpcy50b1N0cmluZygnaGV4JywgMCwgbWF4KS5tYXRjaCgvLnsyfS9nKS5qb2luKCcgJylcbiAgICBpZiAodGhpcy5sZW5ndGggPiBtYXgpIHN0ciArPSAnIC4uLiAnXG4gIH1cbiAgcmV0dXJuICc8QnVmZmVyICcgKyBzdHIgKyAnPidcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpXG4gIGlmICh0aGlzID09PSBiKSByZXR1cm4gMFxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYilcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbmRleE9mID0gZnVuY3Rpb24gaW5kZXhPZiAodmFsLCBieXRlT2Zmc2V0KSB7XG4gIGlmIChieXRlT2Zmc2V0ID4gMHg3ZmZmZmZmZikgYnl0ZU9mZnNldCA9IDB4N2ZmZmZmZmZcbiAgZWxzZSBpZiAoYnl0ZU9mZnNldCA8IC0weDgwMDAwMDAwKSBieXRlT2Zmc2V0ID0gLTB4ODAwMDAwMDBcbiAgYnl0ZU9mZnNldCA+Pj0gMFxuXG4gIGlmICh0aGlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xXG4gIGlmIChieXRlT2Zmc2V0ID49IHRoaXMubGVuZ3RoKSByZXR1cm4gLTFcblxuICAvLyBOZWdhdGl2ZSBvZmZzZXRzIHN0YXJ0IGZyb20gdGhlIGVuZCBvZiB0aGUgYnVmZmVyXG4gIGlmIChieXRlT2Zmc2V0IDwgMCkgYnl0ZU9mZnNldCA9IE1hdGgubWF4KHRoaXMubGVuZ3RoICsgYnl0ZU9mZnNldCwgMClcblxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICBpZiAodmFsLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xIC8vIHNwZWNpYWwgY2FzZTogbG9va2luZyBmb3IgZW1wdHkgc3RyaW5nIGFsd2F5cyBmYWlsc1xuICAgIHJldHVybiBTdHJpbmcucHJvdG90eXBlLmluZGV4T2YuY2FsbCh0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gIH1cbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcih2YWwpKSB7XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gIH1cbiAgaWYgKHR5cGVvZiB2YWwgPT09ICdudW1iZXInKSB7XG4gICAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUICYmIFVpbnQ4QXJyYXkucHJvdG90eXBlLmluZGV4T2YgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHJldHVybiBVaW50OEFycmF5LnByb3RvdHlwZS5pbmRleE9mLmNhbGwodGhpcywgdmFsLCBieXRlT2Zmc2V0KVxuICAgIH1cbiAgICByZXR1cm4gYXJyYXlJbmRleE9mKHRoaXMsIFsgdmFsIF0sIGJ5dGVPZmZzZXQpXG4gIH1cblxuICBmdW5jdGlvbiBhcnJheUluZGV4T2YgKGFyciwgdmFsLCBieXRlT2Zmc2V0KSB7XG4gICAgdmFyIGZvdW5kSW5kZXggPSAtMVxuICAgIGZvciAodmFyIGkgPSAwOyBieXRlT2Zmc2V0ICsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGFycltieXRlT2Zmc2V0ICsgaV0gPT09IHZhbFtmb3VuZEluZGV4ID09PSAtMSA/IDAgOiBpIC0gZm91bmRJbmRleF0pIHtcbiAgICAgICAgaWYgKGZvdW5kSW5kZXggPT09IC0xKSBmb3VuZEluZGV4ID0gaVxuICAgICAgICBpZiAoaSAtIGZvdW5kSW5kZXggKyAxID09PSB2YWwubGVuZ3RoKSByZXR1cm4gYnl0ZU9mZnNldCArIGZvdW5kSW5kZXhcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvdW5kSW5kZXggPSAtMVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gLTFcbiAgfVxuXG4gIHRocm93IG5ldyBUeXBlRXJyb3IoJ3ZhbCBtdXN0IGJlIHN0cmluZywgbnVtYmVyIG9yIEJ1ZmZlcicpXG59XG5cbi8vIGBnZXRgIGlzIGRlcHJlY2F0ZWRcbkJ1ZmZlci5wcm90b3R5cGUuZ2V0ID0gZnVuY3Rpb24gZ2V0IChvZmZzZXQpIHtcbiAgY29uc29sZS5sb2coJy5nZXQoKSBpcyBkZXByZWNhdGVkLiBBY2Nlc3MgdXNpbmcgYXJyYXkgaW5kZXhlcyBpbnN0ZWFkLicpXG4gIHJldHVybiB0aGlzLnJlYWRVSW50OChvZmZzZXQpXG59XG5cbi8vIGBzZXRgIGlzIGRlcHJlY2F0ZWRcbkJ1ZmZlci5wcm90b3R5cGUuc2V0ID0gZnVuY3Rpb24gc2V0ICh2LCBvZmZzZXQpIHtcbiAgY29uc29sZS5sb2coJy5zZXQoKSBpcyBkZXByZWNhdGVkLiBBY2Nlc3MgdXNpbmcgYXJyYXkgaW5kZXhlcyBpbnN0ZWFkLicpXG4gIHJldHVybiB0aGlzLndyaXRlVUludDgodiwgb2Zmc2V0KVxufVxuXG5mdW5jdGlvbiBoZXhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIG9mZnNldCA9IE51bWJlcihvZmZzZXQpIHx8IDBcbiAgdmFyIHJlbWFpbmluZyA9IGJ1Zi5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKCFsZW5ndGgpIHtcbiAgICBsZW5ndGggPSByZW1haW5pbmdcbiAgfSBlbHNlIHtcbiAgICBsZW5ndGggPSBOdW1iZXIobGVuZ3RoKVxuICAgIGlmIChsZW5ndGggPiByZW1haW5pbmcpIHtcbiAgICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICAgIH1cbiAgfVxuXG4gIC8vIG11c3QgYmUgYW4gZXZlbiBudW1iZXIgb2YgZGlnaXRzXG4gIHZhciBzdHJMZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChzdHJMZW4gJSAyICE9PSAwKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGV4IHN0cmluZycpXG5cbiAgaWYgKGxlbmd0aCA+IHN0ckxlbiAvIDIpIHtcbiAgICBsZW5ndGggPSBzdHJMZW4gLyAyXG4gIH1cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIHZhciBwYXJzZWQgPSBwYXJzZUludChzdHJpbmcuc3Vic3RyKGkgKiAyLCAyKSwgMTYpXG4gICAgaWYgKGlzTmFOKHBhcnNlZCkpIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSBwYXJzZWRcbiAgfVxuICByZXR1cm4gaVxufVxuXG5mdW5jdGlvbiB1dGY4V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcih1dGY4VG9CeXRlcyhzdHJpbmcsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBhc2NpaVdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIoYXNjaWlUb0J5dGVzKHN0cmluZyksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGJpbmFyeVdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGFzY2lpV3JpdGUoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBiYXNlNjRXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKGJhc2U2NFRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gdWNzMldyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIodXRmMTZsZVRvQnl0ZXMoc3RyaW5nLCBidWYubGVuZ3RoIC0gb2Zmc2V0KSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZSA9IGZ1bmN0aW9uIHdyaXRlIChzdHJpbmcsIG9mZnNldCwgbGVuZ3RoLCBlbmNvZGluZykge1xuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nKVxuICBpZiAob2Zmc2V0ID09PSB1bmRlZmluZWQpIHtcbiAgICBlbmNvZGluZyA9ICd1dGY4J1xuICAgIGxlbmd0aCA9IHRoaXMubGVuZ3RoXG4gICAgb2Zmc2V0ID0gMFxuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nLCBlbmNvZGluZylcbiAgfSBlbHNlIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygb2Zmc2V0ID09PSAnc3RyaW5nJykge1xuICAgIGVuY29kaW5nID0gb2Zmc2V0XG4gICAgbGVuZ3RoID0gdGhpcy5sZW5ndGhcbiAgICBvZmZzZXQgPSAwXG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcsIG9mZnNldFssIGxlbmd0aF1bLCBlbmNvZGluZ10pXG4gIH0gZWxzZSBpZiAoaXNGaW5pdGUob2Zmc2V0KSkge1xuICAgIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgICBpZiAoaXNGaW5pdGUobGVuZ3RoKSkge1xuICAgICAgbGVuZ3RoID0gbGVuZ3RoIHwgMFxuICAgICAgaWYgKGVuY29kaW5nID09PSB1bmRlZmluZWQpIGVuY29kaW5nID0gJ3V0ZjgnXG4gICAgfSBlbHNlIHtcbiAgICAgIGVuY29kaW5nID0gbGVuZ3RoXG4gICAgICBsZW5ndGggPSB1bmRlZmluZWRcbiAgICB9XG4gIC8vIGxlZ2FjeSB3cml0ZShzdHJpbmcsIGVuY29kaW5nLCBvZmZzZXQsIGxlbmd0aCkgLSByZW1vdmUgaW4gdjAuMTNcbiAgfSBlbHNlIHtcbiAgICB2YXIgc3dhcCA9IGVuY29kaW5nXG4gICAgZW5jb2RpbmcgPSBvZmZzZXRcbiAgICBvZmZzZXQgPSBsZW5ndGggfCAwXG4gICAgbGVuZ3RoID0gc3dhcFxuICB9XG5cbiAgdmFyIHJlbWFpbmluZyA9IHRoaXMubGVuZ3RoIC0gb2Zmc2V0XG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCB8fCBsZW5ndGggPiByZW1haW5pbmcpIGxlbmd0aCA9IHJlbWFpbmluZ1xuXG4gIGlmICgoc3RyaW5nLmxlbmd0aCA+IDAgJiYgKGxlbmd0aCA8IDAgfHwgb2Zmc2V0IDwgMCkpIHx8IG9mZnNldCA+IHRoaXMubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2F0dGVtcHQgdG8gd3JpdGUgb3V0c2lkZSBidWZmZXIgYm91bmRzJylcbiAgfVxuXG4gIGlmICghZW5jb2RpbmcpIGVuY29kaW5nID0gJ3V0ZjgnXG5cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBoZXhXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICAgIHJldHVybiBhc2NpaVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAgIHJldHVybiBiaW5hcnlXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICAvLyBXYXJuaW5nOiBtYXhMZW5ndGggbm90IHRha2VuIGludG8gYWNjb3VudCBpbiBiYXNlNjRXcml0ZVxuICAgICAgICByZXR1cm4gYmFzZTY0V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIHVjczJXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBlbmNvZGluZylcbiAgICAgICAgZW5jb2RpbmcgPSAoJycgKyBlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS50b0pTT04gPSBmdW5jdGlvbiB0b0pTT04gKCkge1xuICByZXR1cm4ge1xuICAgIHR5cGU6ICdCdWZmZXInLFxuICAgIGRhdGE6IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHRoaXMuX2FyciB8fCB0aGlzLCAwKVxuICB9XG59XG5cbmZ1bmN0aW9uIGJhc2U2NFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgaWYgKHN0YXJ0ID09PSAwICYmIGVuZCA9PT0gYnVmLmxlbmd0aCkge1xuICAgIHJldHVybiBiYXNlNjQuZnJvbUJ5dGVBcnJheShidWYpXG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIGJhc2U2NC5mcm9tQnl0ZUFycmF5KGJ1Zi5zbGljZShzdGFydCwgZW5kKSlcbiAgfVxufVxuXG5mdW5jdGlvbiB1dGY4U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG4gIHZhciByZXMgPSBbXVxuXG4gIHZhciBpID0gc3RhcnRcbiAgd2hpbGUgKGkgPCBlbmQpIHtcbiAgICB2YXIgZmlyc3RCeXRlID0gYnVmW2ldXG4gICAgdmFyIGNvZGVQb2ludCA9IG51bGxcbiAgICB2YXIgYnl0ZXNQZXJTZXF1ZW5jZSA9IChmaXJzdEJ5dGUgPiAweEVGKSA/IDRcbiAgICAgIDogKGZpcnN0Qnl0ZSA+IDB4REYpID8gM1xuICAgICAgOiAoZmlyc3RCeXRlID4gMHhCRikgPyAyXG4gICAgICA6IDFcblxuICAgIGlmIChpICsgYnl0ZXNQZXJTZXF1ZW5jZSA8PSBlbmQpIHtcbiAgICAgIHZhciBzZWNvbmRCeXRlLCB0aGlyZEJ5dGUsIGZvdXJ0aEJ5dGUsIHRlbXBDb2RlUG9pbnRcblxuICAgICAgc3dpdGNoIChieXRlc1BlclNlcXVlbmNlKSB7XG4gICAgICAgIGNhc2UgMTpcbiAgICAgICAgICBpZiAoZmlyc3RCeXRlIDwgMHg4MCkge1xuICAgICAgICAgICAgY29kZVBvaW50ID0gZmlyc3RCeXRlXG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgMjpcbiAgICAgICAgICBzZWNvbmRCeXRlID0gYnVmW2kgKyAxXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4MUYpIDw8IDB4NiB8IChzZWNvbmRCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHg3Rikge1xuICAgICAgICAgICAgICBjb2RlUG9pbnQgPSB0ZW1wQ29kZVBvaW50XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgMzpcbiAgICAgICAgICBzZWNvbmRCeXRlID0gYnVmW2kgKyAxXVxuICAgICAgICAgIHRoaXJkQnl0ZSA9IGJ1ZltpICsgMl1cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAodGhpcmRCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHhGKSA8PCAweEMgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpIDw8IDB4NiB8ICh0aGlyZEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweDdGRiAmJiAodGVtcENvZGVQb2ludCA8IDB4RDgwMCB8fCB0ZW1wQ29kZVBvaW50ID4gMHhERkZGKSkge1xuICAgICAgICAgICAgICBjb2RlUG9pbnQgPSB0ZW1wQ29kZVBvaW50XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgNDpcbiAgICAgICAgICBzZWNvbmRCeXRlID0gYnVmW2kgKyAxXVxuICAgICAgICAgIHRoaXJkQnl0ZSA9IGJ1ZltpICsgMl1cbiAgICAgICAgICBmb3VydGhCeXRlID0gYnVmW2kgKyAzXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwICYmICh0aGlyZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAoZm91cnRoQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4RikgPDwgMHgxMiB8IChzZWNvbmRCeXRlICYgMHgzRikgPDwgMHhDIHwgKHRoaXJkQnl0ZSAmIDB4M0YpIDw8IDB4NiB8IChmb3VydGhCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHhGRkZGICYmIHRlbXBDb2RlUG9pbnQgPCAweDExMDAwMCkge1xuICAgICAgICAgICAgICBjb2RlUG9pbnQgPSB0ZW1wQ29kZVBvaW50XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChjb2RlUG9pbnQgPT09IG51bGwpIHtcbiAgICAgIC8vIHdlIGRpZCBub3QgZ2VuZXJhdGUgYSB2YWxpZCBjb2RlUG9pbnQgc28gaW5zZXJ0IGFcbiAgICAgIC8vIHJlcGxhY2VtZW50IGNoYXIgKFUrRkZGRCkgYW5kIGFkdmFuY2Ugb25seSAxIGJ5dGVcbiAgICAgIGNvZGVQb2ludCA9IDB4RkZGRFxuICAgICAgYnl0ZXNQZXJTZXF1ZW5jZSA9IDFcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA+IDB4RkZGRikge1xuICAgICAgLy8gZW5jb2RlIHRvIHV0ZjE2IChzdXJyb2dhdGUgcGFpciBkYW5jZSlcbiAgICAgIGNvZGVQb2ludCAtPSAweDEwMDAwXG4gICAgICByZXMucHVzaChjb2RlUG9pbnQgPj4+IDEwICYgMHgzRkYgfCAweEQ4MDApXG4gICAgICBjb2RlUG9pbnQgPSAweERDMDAgfCBjb2RlUG9pbnQgJiAweDNGRlxuICAgIH1cblxuICAgIHJlcy5wdXNoKGNvZGVQb2ludClcbiAgICBpICs9IGJ5dGVzUGVyU2VxdWVuY2VcbiAgfVxuXG4gIHJldHVybiBkZWNvZGVDb2RlUG9pbnRzQXJyYXkocmVzKVxufVxuXG4vLyBCYXNlZCBvbiBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8yMjc0NzI3Mi82ODA3NDIsIHRoZSBicm93c2VyIHdpdGhcbi8vIHRoZSBsb3dlc3QgbGltaXQgaXMgQ2hyb21lLCB3aXRoIDB4MTAwMDAgYXJncy5cbi8vIFdlIGdvIDEgbWFnbml0dWRlIGxlc3MsIGZvciBzYWZldHlcbnZhciBNQVhfQVJHVU1FTlRTX0xFTkdUSCA9IDB4MTAwMFxuXG5mdW5jdGlvbiBkZWNvZGVDb2RlUG9pbnRzQXJyYXkgKGNvZGVQb2ludHMpIHtcbiAgdmFyIGxlbiA9IGNvZGVQb2ludHMubGVuZ3RoXG4gIGlmIChsZW4gPD0gTUFYX0FSR1VNRU5UU19MRU5HVEgpIHtcbiAgICByZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShTdHJpbmcsIGNvZGVQb2ludHMpIC8vIGF2b2lkIGV4dHJhIHNsaWNlKClcbiAgfVxuXG4gIC8vIERlY29kZSBpbiBjaHVua3MgdG8gYXZvaWQgXCJjYWxsIHN0YWNrIHNpemUgZXhjZWVkZWRcIi5cbiAgdmFyIHJlcyA9ICcnXG4gIHZhciBpID0gMFxuICB3aGlsZSAoaSA8IGxlbikge1xuICAgIHJlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFxuICAgICAgU3RyaW5nLFxuICAgICAgY29kZVBvaW50cy5zbGljZShpLCBpICs9IE1BWF9BUkdVTUVOVFNfTEVOR1RIKVxuICAgIClcbiAgfVxuICByZXR1cm4gcmVzXG59XG5cbmZ1bmN0aW9uIGFzY2lpU2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgcmV0ID0gJydcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgcmV0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnVmW2ldICYgMHg3RilcbiAgfVxuICByZXR1cm4gcmV0XG59XG5cbmZ1bmN0aW9uIGJpbmFyeVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIHJldCA9ICcnXG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcblxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIHJldCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ1ZltpXSlcbiAgfVxuICByZXR1cm4gcmV0XG59XG5cbmZ1bmN0aW9uIGhleFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxlbiA9IGJ1Zi5sZW5ndGhcblxuICBpZiAoIXN0YXJ0IHx8IHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIGlmICghZW5kIHx8IGVuZCA8IDAgfHwgZW5kID4gbGVuKSBlbmQgPSBsZW5cblxuICB2YXIgb3V0ID0gJydcbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICBvdXQgKz0gdG9IZXgoYnVmW2ldKVxuICB9XG4gIHJldHVybiBvdXRcbn1cblxuZnVuY3Rpb24gdXRmMTZsZVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGJ5dGVzID0gYnVmLnNsaWNlKHN0YXJ0LCBlbmQpXG4gIHZhciByZXMgPSAnJ1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSArPSAyKSB7XG4gICAgcmVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnl0ZXNbaV0gKyBieXRlc1tpICsgMV0gKiAyNTYpXG4gIH1cbiAgcmV0dXJuIHJlc1xufVxuXG5CdWZmZXIucHJvdG90eXBlLnNsaWNlID0gZnVuY3Rpb24gc2xpY2UgKHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxlbiA9IHRoaXMubGVuZ3RoXG4gIHN0YXJ0ID0gfn5zdGFydFxuICBlbmQgPSBlbmQgPT09IHVuZGVmaW5lZCA/IGxlbiA6IH5+ZW5kXG5cbiAgaWYgKHN0YXJ0IDwgMCkge1xuICAgIHN0YXJ0ICs9IGxlblxuICAgIGlmIChzdGFydCA8IDApIHN0YXJ0ID0gMFxuICB9IGVsc2UgaWYgKHN0YXJ0ID4gbGVuKSB7XG4gICAgc3RhcnQgPSBsZW5cbiAgfVxuXG4gIGlmIChlbmQgPCAwKSB7XG4gICAgZW5kICs9IGxlblxuICAgIGlmIChlbmQgPCAwKSBlbmQgPSAwXG4gIH0gZWxzZSBpZiAoZW5kID4gbGVuKSB7XG4gICAgZW5kID0gbGVuXG4gIH1cblxuICBpZiAoZW5kIDwgc3RhcnQpIGVuZCA9IHN0YXJ0XG5cbiAgdmFyIG5ld0J1ZlxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICBuZXdCdWYgPSBCdWZmZXIuX2F1Z21lbnQodGhpcy5zdWJhcnJheShzdGFydCwgZW5kKSlcbiAgfSBlbHNlIHtcbiAgICB2YXIgc2xpY2VMZW4gPSBlbmQgLSBzdGFydFxuICAgIG5ld0J1ZiA9IG5ldyBCdWZmZXIoc2xpY2VMZW4sIHVuZGVmaW5lZClcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNsaWNlTGVuOyBpKyspIHtcbiAgICAgIG5ld0J1ZltpXSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfVxuXG4gIGlmIChuZXdCdWYubGVuZ3RoKSBuZXdCdWYucGFyZW50ID0gdGhpcy5wYXJlbnQgfHwgdGhpc1xuXG4gIHJldHVybiBuZXdCdWZcbn1cblxuLypcbiAqIE5lZWQgdG8gbWFrZSBzdXJlIHRoYXQgYnVmZmVyIGlzbid0IHRyeWluZyB0byB3cml0ZSBvdXQgb2YgYm91bmRzLlxuICovXG5mdW5jdGlvbiBjaGVja09mZnNldCAob2Zmc2V0LCBleHQsIGxlbmd0aCkge1xuICBpZiAoKG9mZnNldCAlIDEpICE9PSAwIHx8IG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdvZmZzZXQgaXMgbm90IHVpbnQnKVxuICBpZiAob2Zmc2V0ICsgZXh0ID4gbGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignVHJ5aW5nIHRvIGFjY2VzcyBiZXlvbmQgYnVmZmVyIGxlbmd0aCcpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnRMRSA9IGZ1bmN0aW9uIHJlYWRVSW50TEUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIGldICogbXVsXG4gIH1cblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnRCRSA9IGZ1bmN0aW9uIHJlYWRVSW50QkUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG4gIH1cblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAtLWJ5dGVMZW5ndGhdXG4gIHZhciBtdWwgPSAxXG4gIHdoaWxlIChieXRlTGVuZ3RoID4gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIC0tYnl0ZUxlbmd0aF0gKiBtdWxcbiAgfVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDggPSBmdW5jdGlvbiByZWFkVUludDggKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAxLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIHRoaXNbb2Zmc2V0XVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MTZMRSA9IGZ1bmN0aW9uIHJlYWRVSW50MTZMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gdGhpc1tvZmZzZXRdIHwgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDE2QkUgPSBmdW5jdGlvbiByZWFkVUludDE2QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuICh0aGlzW29mZnNldF0gPDwgOCkgfCB0aGlzW29mZnNldCArIDFdXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQzMkxFID0gZnVuY3Rpb24gcmVhZFVJbnQzMkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICgodGhpc1tvZmZzZXRdKSB8XG4gICAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KSB8XG4gICAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCAxNikpICtcbiAgICAgICh0aGlzW29mZnNldCArIDNdICogMHgxMDAwMDAwKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MzJCRSA9IGZ1bmN0aW9uIHJlYWRVSW50MzJCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAodGhpc1tvZmZzZXRdICogMHgxMDAwMDAwKSArXG4gICAgKCh0aGlzW29mZnNldCArIDFdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgOCkgfFxuICAgIHRoaXNbb2Zmc2V0ICsgM10pXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludExFID0gZnVuY3Rpb24gcmVhZEludExFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XVxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyBpXSAqIG11bFxuICB9XG4gIG11bCAqPSAweDgwXG5cbiAgaWYgKHZhbCA+PSBtdWwpIHZhbCAtPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aClcblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludEJFID0gZnVuY3Rpb24gcmVhZEludEJFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIGkgPSBieXRlTGVuZ3RoXG4gIHZhciBtdWwgPSAxXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIC0taV1cbiAgd2hpbGUgKGkgPiAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgLS1pXSAqIG11bFxuICB9XG4gIG11bCAqPSAweDgwXG5cbiAgaWYgKHZhbCA+PSBtdWwpIHZhbCAtPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aClcblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDggPSBmdW5jdGlvbiByZWFkSW50OCAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDEsIHRoaXMubGVuZ3RoKVxuICBpZiAoISh0aGlzW29mZnNldF0gJiAweDgwKSkgcmV0dXJuICh0aGlzW29mZnNldF0pXG4gIHJldHVybiAoKDB4ZmYgLSB0aGlzW29mZnNldF0gKyAxKSAqIC0xKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQxNkxFID0gZnVuY3Rpb24gcmVhZEludDE2TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XSB8ICh0aGlzW29mZnNldCArIDFdIDw8IDgpXG4gIHJldHVybiAodmFsICYgMHg4MDAwKSA/IHZhbCB8IDB4RkZGRjAwMDAgOiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MTZCRSA9IGZ1bmN0aW9uIHJlYWRJbnQxNkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIDFdIHwgKHRoaXNbb2Zmc2V0XSA8PCA4KVxuICByZXR1cm4gKHZhbCAmIDB4ODAwMCkgPyB2YWwgfCAweEZGRkYwMDAwIDogdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDMyTEUgPSBmdW5jdGlvbiByZWFkSW50MzJMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAodGhpc1tvZmZzZXRdKSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOCkgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgM10gPDwgMjQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDMyQkUgPSBmdW5jdGlvbiByZWFkSW50MzJCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAodGhpc1tvZmZzZXRdIDw8IDI0KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCA4KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgM10pXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEZsb2F0TEUgPSBmdW5jdGlvbiByZWFkRmxvYXRMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgdHJ1ZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEZsb2F0QkUgPSBmdW5jdGlvbiByZWFkRmxvYXRCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgZmFsc2UsIDIzLCA0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWREb3VibGVMRSA9IGZ1bmN0aW9uIHJlYWREb3VibGVMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDgsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgdHJ1ZSwgNTIsIDgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUJFID0gZnVuY3Rpb24gcmVhZERvdWJsZUJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgOCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCBmYWxzZSwgNTIsIDgpXG59XG5cbmZ1bmN0aW9uIGNoZWNrSW50IChidWYsIHZhbHVlLCBvZmZzZXQsIGV4dCwgbWF4LCBtaW4pIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoYnVmKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignYnVmZmVyIG11c3QgYmUgYSBCdWZmZXIgaW5zdGFuY2UnKVxuICBpZiAodmFsdWUgPiBtYXggfHwgdmFsdWUgPCBtaW4pIHRocm93IG5ldyBSYW5nZUVycm9yKCd2YWx1ZSBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludExFID0gZnVuY3Rpb24gd3JpdGVVSW50TEUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKSwgMClcblxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludEJFID0gZnVuY3Rpb24gd3JpdGVVSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKSwgMClcblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDggPSBmdW5jdGlvbiB3cml0ZVVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4ZmYsIDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MTYgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgMik7IGkgPCBqOyBpKyspIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgJiAoMHhmZiA8PCAoOCAqIChsaXR0bGVFbmRpYW4gPyBpIDogMSAtIGkpKSkpID4+PlxuICAgICAgKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkgKiA4XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlVUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHhmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MzIgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBmb3IgKHZhciBpID0gMCwgaiA9IE1hdGgubWluKGJ1Zi5sZW5ndGggLSBvZmZzZXQsIDQpOyBpIDwgajsgaSsrKSB7XG4gICAgYnVmW29mZnNldCArIGldID0gKHZhbHVlID4+PiAobGl0dGxlRW5kaWFuID8gaSA6IDMgLSBpKSAqIDgpICYgMHhmZlxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlVUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHhmZmZmZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludExFID0gZnVuY3Rpb24gd3JpdGVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IDBcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHN1YiA9IHZhbHVlIDwgMCA/IDEgOiAwXG4gIHRoaXNbb2Zmc2V0XSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAoKHZhbHVlIC8gbXVsKSA+PiAwKSAtIHN1YiAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnRCRSA9IGZ1bmN0aW9uIHdyaXRlSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIHZhciBsaW1pdCA9IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoIC0gMSlcblxuICAgIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIGxpbWl0IC0gMSwgLWxpbWl0KVxuICB9XG5cbiAgdmFyIGkgPSBieXRlTGVuZ3RoIC0gMVxuICB2YXIgbXVsID0gMVxuICB2YXIgc3ViID0gdmFsdWUgPCAwID8gMSA6IDBcbiAgdGhpc1tvZmZzZXQgKyBpXSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoLS1pID49IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKCh2YWx1ZSAvIG11bCkgPj4gMCkgLSBzdWIgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50OCA9IGZ1bmN0aW9uIHdyaXRlSW50OCAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAxLCAweDdmLCAtMHg4MClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkgdmFsdWUgPSBNYXRoLmZsb29yKHZhbHVlKVxuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmYgKyB2YWx1ZSArIDFcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDE2TEUgPSBmdW5jdGlvbiB3cml0ZUludDE2TEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHg3ZmZmLCAtMHg4MDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlSW50MTZCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweDdmZmYsIC0weDgwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlSW50MzJMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweDdmZmZmZmZmLCAtMHg4MDAwMDAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgPj4+IDI0KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDMyQkUgPSBmdW5jdGlvbiB3cml0ZUludDMyQkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHg3ZmZmZmZmZiwgLTB4ODAwMDAwMDApXG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuZnVuY3Rpb24gY2hlY2tJRUVFNzU0IChidWYsIHZhbHVlLCBvZmZzZXQsIGV4dCwgbWF4LCBtaW4pIHtcbiAgaWYgKHZhbHVlID4gbWF4IHx8IHZhbHVlIDwgbWluKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcigndmFsdWUgaXMgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBidWYubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignaW5kZXggb3V0IG9mIHJhbmdlJylcbiAgaWYgKG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5mdW5jdGlvbiB3cml0ZUZsb2F0IChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDQsIDMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgsIC0zLjQwMjgyMzQ2NjM4NTI4ODZlKzM4KVxuICB9XG4gIGllZWU3NTQud3JpdGUoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4sIDIzLCA0KVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRmxvYXRMRSA9IGZ1bmN0aW9uIHdyaXRlRmxvYXRMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRmxvYXQodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSwgbm9Bc3NlcnQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdEJFID0gZnVuY3Rpb24gd3JpdGVGbG9hdEJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSwgbm9Bc3NlcnQpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRG91YmxlIChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDgsIDEuNzk3NjkzMTM0ODYyMzE1N0UrMzA4LCAtMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgNTIsIDgpXG4gIHJldHVybiBvZmZzZXQgKyA4XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVEb3VibGVMRSA9IGZ1bmN0aW9uIHdyaXRlRG91YmxlTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZURvdWJsZSh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUJFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuLy8gY29weSh0YXJnZXRCdWZmZXIsIHRhcmdldFN0YXJ0PTAsIHNvdXJjZVN0YXJ0PTAsIHNvdXJjZUVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5jb3B5ID0gZnVuY3Rpb24gY29weSAodGFyZ2V0LCB0YXJnZXRTdGFydCwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXN0YXJ0KSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgJiYgZW5kICE9PSAwKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0U3RhcnQgPj0gdGFyZ2V0Lmxlbmd0aCkgdGFyZ2V0U3RhcnQgPSB0YXJnZXQubGVuZ3RoXG4gIGlmICghdGFyZ2V0U3RhcnQpIHRhcmdldFN0YXJ0ID0gMFxuICBpZiAoZW5kID4gMCAmJiBlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICAvLyBDb3B5IDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVybiAwXG4gIGlmICh0YXJnZXQubGVuZ3RoID09PSAwIHx8IHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gMFxuXG4gIC8vIEZhdGFsIGVycm9yIGNvbmRpdGlvbnNcbiAgaWYgKHRhcmdldFN0YXJ0IDwgMCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCd0YXJnZXRTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgfVxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlU3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlRW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIC8vIEFyZSB3ZSBvb2I/XG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKHRhcmdldC5sZW5ndGggLSB0YXJnZXRTdGFydCA8IGVuZCAtIHN0YXJ0KSB7XG4gICAgZW5kID0gdGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0ICsgc3RhcnRcbiAgfVxuXG4gIHZhciBsZW4gPSBlbmQgLSBzdGFydFxuICB2YXIgaVxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQgJiYgc3RhcnQgPCB0YXJnZXRTdGFydCAmJiB0YXJnZXRTdGFydCA8IGVuZCkge1xuICAgIC8vIGRlc2NlbmRpbmcgY29weSBmcm9tIGVuZFxuICAgIGZvciAoaSA9IGxlbiAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICB0YXJnZXRbaSArIHRhcmdldFN0YXJ0XSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfSBlbHNlIGlmIChsZW4gPCAxMDAwIHx8ICFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIGFzY2VuZGluZyBjb3B5IGZyb20gc3RhcnRcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHRhcmdldC5fc2V0KHRoaXMuc3ViYXJyYXkoc3RhcnQsIHN0YXJ0ICsgbGVuKSwgdGFyZ2V0U3RhcnQpXG4gIH1cblxuICByZXR1cm4gbGVuXG59XG5cbi8vIGZpbGwodmFsdWUsIHN0YXJ0PTAsIGVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5maWxsID0gZnVuY3Rpb24gZmlsbCAodmFsdWUsIHN0YXJ0LCBlbmQpIHtcbiAgaWYgKCF2YWx1ZSkgdmFsdWUgPSAwXG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCkgZW5kID0gdGhpcy5sZW5ndGhcblxuICBpZiAoZW5kIDwgc3RhcnQpIHRocm93IG5ldyBSYW5nZUVycm9yKCdlbmQgPCBzdGFydCcpXG5cbiAgLy8gRmlsbCAwIGJ5dGVzOyB3ZSdyZSBkb25lXG4gIGlmIChlbmQgPT09IHN0YXJ0KSByZXR1cm5cbiAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm5cblxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwIHx8IGVuZCA+IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignZW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIHZhciBpXG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdGhpc1tpXSA9IHZhbHVlXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHZhciBieXRlcyA9IHV0ZjhUb0J5dGVzKHZhbHVlLnRvU3RyaW5nKCkpXG4gICAgdmFyIGxlbiA9IGJ5dGVzLmxlbmd0aFxuICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICAgIHRoaXNbaV0gPSBieXRlc1tpICUgbGVuXVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzXG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBgQXJyYXlCdWZmZXJgIHdpdGggdGhlICpjb3BpZWQqIG1lbW9yeSBvZiB0aGUgYnVmZmVyIGluc3RhbmNlLlxuICogQWRkZWQgaW4gTm9kZSAwLjEyLiBPbmx5IGF2YWlsYWJsZSBpbiBicm93c2VycyB0aGF0IHN1cHBvcnQgQXJyYXlCdWZmZXIuXG4gKi9cbkJ1ZmZlci5wcm90b3R5cGUudG9BcnJheUJ1ZmZlciA9IGZ1bmN0aW9uIHRvQXJyYXlCdWZmZXIgKCkge1xuICBpZiAodHlwZW9mIFVpbnQ4QXJyYXkgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgICByZXR1cm4gKG5ldyBCdWZmZXIodGhpcykpLmJ1ZmZlclxuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgYnVmID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5sZW5ndGgpXG4gICAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gYnVmLmxlbmd0aDsgaSA8IGxlbjsgaSArPSAxKSB7XG4gICAgICAgIGJ1ZltpXSA9IHRoaXNbaV1cbiAgICAgIH1cbiAgICAgIHJldHVybiBidWYuYnVmZmVyXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0J1ZmZlci50b0FycmF5QnVmZmVyIG5vdCBzdXBwb3J0ZWQgaW4gdGhpcyBicm93c2VyJylcbiAgfVxufVxuXG4vLyBIRUxQRVIgRlVOQ1RJT05TXG4vLyA9PT09PT09PT09PT09PT09XG5cbnZhciBCUCA9IEJ1ZmZlci5wcm90b3R5cGVcblxuLyoqXG4gKiBBdWdtZW50IGEgVWludDhBcnJheSAqaW5zdGFuY2UqIChub3QgdGhlIFVpbnQ4QXJyYXkgY2xhc3MhKSB3aXRoIEJ1ZmZlciBtZXRob2RzXG4gKi9cbkJ1ZmZlci5fYXVnbWVudCA9IGZ1bmN0aW9uIF9hdWdtZW50IChhcnIpIHtcbiAgYXJyLmNvbnN0cnVjdG9yID0gQnVmZmVyXG4gIGFyci5faXNCdWZmZXIgPSB0cnVlXG5cbiAgLy8gc2F2ZSByZWZlcmVuY2UgdG8gb3JpZ2luYWwgVWludDhBcnJheSBzZXQgbWV0aG9kIGJlZm9yZSBvdmVyd3JpdGluZ1xuICBhcnIuX3NldCA9IGFyci5zZXRcblxuICAvLyBkZXByZWNhdGVkXG4gIGFyci5nZXQgPSBCUC5nZXRcbiAgYXJyLnNldCA9IEJQLnNldFxuXG4gIGFyci53cml0ZSA9IEJQLndyaXRlXG4gIGFyci50b1N0cmluZyA9IEJQLnRvU3RyaW5nXG4gIGFyci50b0xvY2FsZVN0cmluZyA9IEJQLnRvU3RyaW5nXG4gIGFyci50b0pTT04gPSBCUC50b0pTT05cbiAgYXJyLmVxdWFscyA9IEJQLmVxdWFsc1xuICBhcnIuY29tcGFyZSA9IEJQLmNvbXBhcmVcbiAgYXJyLmluZGV4T2YgPSBCUC5pbmRleE9mXG4gIGFyci5jb3B5ID0gQlAuY29weVxuICBhcnIuc2xpY2UgPSBCUC5zbGljZVxuICBhcnIucmVhZFVJbnRMRSA9IEJQLnJlYWRVSW50TEVcbiAgYXJyLnJlYWRVSW50QkUgPSBCUC5yZWFkVUludEJFXG4gIGFyci5yZWFkVUludDggPSBCUC5yZWFkVUludDhcbiAgYXJyLnJlYWRVSW50MTZMRSA9IEJQLnJlYWRVSW50MTZMRVxuICBhcnIucmVhZFVJbnQxNkJFID0gQlAucmVhZFVJbnQxNkJFXG4gIGFyci5yZWFkVUludDMyTEUgPSBCUC5yZWFkVUludDMyTEVcbiAgYXJyLnJlYWRVSW50MzJCRSA9IEJQLnJlYWRVSW50MzJCRVxuICBhcnIucmVhZEludExFID0gQlAucmVhZEludExFXG4gIGFyci5yZWFkSW50QkUgPSBCUC5yZWFkSW50QkVcbiAgYXJyLnJlYWRJbnQ4ID0gQlAucmVhZEludDhcbiAgYXJyLnJlYWRJbnQxNkxFID0gQlAucmVhZEludDE2TEVcbiAgYXJyLnJlYWRJbnQxNkJFID0gQlAucmVhZEludDE2QkVcbiAgYXJyLnJlYWRJbnQzMkxFID0gQlAucmVhZEludDMyTEVcbiAgYXJyLnJlYWRJbnQzMkJFID0gQlAucmVhZEludDMyQkVcbiAgYXJyLnJlYWRGbG9hdExFID0gQlAucmVhZEZsb2F0TEVcbiAgYXJyLnJlYWRGbG9hdEJFID0gQlAucmVhZEZsb2F0QkVcbiAgYXJyLnJlYWREb3VibGVMRSA9IEJQLnJlYWREb3VibGVMRVxuICBhcnIucmVhZERvdWJsZUJFID0gQlAucmVhZERvdWJsZUJFXG4gIGFyci53cml0ZVVJbnQ4ID0gQlAud3JpdGVVSW50OFxuICBhcnIud3JpdGVVSW50TEUgPSBCUC53cml0ZVVJbnRMRVxuICBhcnIud3JpdGVVSW50QkUgPSBCUC53cml0ZVVJbnRCRVxuICBhcnIud3JpdGVVSW50MTZMRSA9IEJQLndyaXRlVUludDE2TEVcbiAgYXJyLndyaXRlVUludDE2QkUgPSBCUC53cml0ZVVJbnQxNkJFXG4gIGFyci53cml0ZVVJbnQzMkxFID0gQlAud3JpdGVVSW50MzJMRVxuICBhcnIud3JpdGVVSW50MzJCRSA9IEJQLndyaXRlVUludDMyQkVcbiAgYXJyLndyaXRlSW50TEUgPSBCUC53cml0ZUludExFXG4gIGFyci53cml0ZUludEJFID0gQlAud3JpdGVJbnRCRVxuICBhcnIud3JpdGVJbnQ4ID0gQlAud3JpdGVJbnQ4XG4gIGFyci53cml0ZUludDE2TEUgPSBCUC53cml0ZUludDE2TEVcbiAgYXJyLndyaXRlSW50MTZCRSA9IEJQLndyaXRlSW50MTZCRVxuICBhcnIud3JpdGVJbnQzMkxFID0gQlAud3JpdGVJbnQzMkxFXG4gIGFyci53cml0ZUludDMyQkUgPSBCUC53cml0ZUludDMyQkVcbiAgYXJyLndyaXRlRmxvYXRMRSA9IEJQLndyaXRlRmxvYXRMRVxuICBhcnIud3JpdGVGbG9hdEJFID0gQlAud3JpdGVGbG9hdEJFXG4gIGFyci53cml0ZURvdWJsZUxFID0gQlAud3JpdGVEb3VibGVMRVxuICBhcnIud3JpdGVEb3VibGVCRSA9IEJQLndyaXRlRG91YmxlQkVcbiAgYXJyLmZpbGwgPSBCUC5maWxsXG4gIGFyci5pbnNwZWN0ID0gQlAuaW5zcGVjdFxuICBhcnIudG9BcnJheUJ1ZmZlciA9IEJQLnRvQXJyYXlCdWZmZXJcblxuICByZXR1cm4gYXJyXG59XG5cbnZhciBJTlZBTElEX0JBU0U2NF9SRSA9IC9bXitcXC8wLTlBLVphLXotX10vZ1xuXG5mdW5jdGlvbiBiYXNlNjRjbGVhbiAoc3RyKSB7XG4gIC8vIE5vZGUgc3RyaXBzIG91dCBpbnZhbGlkIGNoYXJhY3RlcnMgbGlrZSBcXG4gYW5kIFxcdCBmcm9tIHRoZSBzdHJpbmcsIGJhc2U2NC1qcyBkb2VzIG5vdFxuICBzdHIgPSBzdHJpbmd0cmltKHN0cikucmVwbGFjZShJTlZBTElEX0JBU0U2NF9SRSwgJycpXG4gIC8vIE5vZGUgY29udmVydHMgc3RyaW5ncyB3aXRoIGxlbmd0aCA8IDIgdG8gJydcbiAgaWYgKHN0ci5sZW5ndGggPCAyKSByZXR1cm4gJydcbiAgLy8gTm9kZSBhbGxvd3MgZm9yIG5vbi1wYWRkZWQgYmFzZTY0IHN0cmluZ3MgKG1pc3NpbmcgdHJhaWxpbmcgPT09KSwgYmFzZTY0LWpzIGRvZXMgbm90XG4gIHdoaWxlIChzdHIubGVuZ3RoICUgNCAhPT0gMCkge1xuICAgIHN0ciA9IHN0ciArICc9J1xuICB9XG4gIHJldHVybiBzdHJcbn1cblxuZnVuY3Rpb24gc3RyaW5ndHJpbSAoc3RyKSB7XG4gIGlmIChzdHIudHJpbSkgcmV0dXJuIHN0ci50cmltKClcbiAgcmV0dXJuIHN0ci5yZXBsYWNlKC9eXFxzK3xcXHMrJC9nLCAnJylcbn1cblxuZnVuY3Rpb24gdG9IZXggKG4pIHtcbiAgaWYgKG4gPCAxNikgcmV0dXJuICcwJyArIG4udG9TdHJpbmcoMTYpXG4gIHJldHVybiBuLnRvU3RyaW5nKDE2KVxufVxuXG5mdW5jdGlvbiB1dGY4VG9CeXRlcyAoc3RyaW5nLCB1bml0cykge1xuICB1bml0cyA9IHVuaXRzIHx8IEluZmluaXR5XG4gIHZhciBjb2RlUG9pbnRcbiAgdmFyIGxlbmd0aCA9IHN0cmluZy5sZW5ndGhcbiAgdmFyIGxlYWRTdXJyb2dhdGUgPSBudWxsXG4gIHZhciBieXRlcyA9IFtdXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIGNvZGVQb2ludCA9IHN0cmluZy5jaGFyQ29kZUF0KGkpXG5cbiAgICAvLyBpcyBzdXJyb2dhdGUgY29tcG9uZW50XG4gICAgaWYgKGNvZGVQb2ludCA+IDB4RDdGRiAmJiBjb2RlUG9pbnQgPCAweEUwMDApIHtcbiAgICAgIC8vIGxhc3QgY2hhciB3YXMgYSBsZWFkXG4gICAgICBpZiAoIWxlYWRTdXJyb2dhdGUpIHtcbiAgICAgICAgLy8gbm8gbGVhZCB5ZXRcbiAgICAgICAgaWYgKGNvZGVQb2ludCA+IDB4REJGRikge1xuICAgICAgICAgIC8vIHVuZXhwZWN0ZWQgdHJhaWxcbiAgICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9IGVsc2UgaWYgKGkgKyAxID09PSBsZW5ndGgpIHtcbiAgICAgICAgICAvLyB1bnBhaXJlZCBsZWFkXG4gICAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHZhbGlkIGxlYWRcbiAgICAgICAgbGVhZFN1cnJvZ2F0ZSA9IGNvZGVQb2ludFxuXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIC8vIDIgbGVhZHMgaW4gYSByb3dcbiAgICAgIGlmIChjb2RlUG9pbnQgPCAweERDMDApIHtcbiAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgIGxlYWRTdXJyb2dhdGUgPSBjb2RlUG9pbnRcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gdmFsaWQgc3Vycm9nYXRlIHBhaXJcbiAgICAgIGNvZGVQb2ludCA9IChsZWFkU3Vycm9nYXRlIC0gMHhEODAwIDw8IDEwIHwgY29kZVBvaW50IC0gMHhEQzAwKSArIDB4MTAwMDBcbiAgICB9IGVsc2UgaWYgKGxlYWRTdXJyb2dhdGUpIHtcbiAgICAgIC8vIHZhbGlkIGJtcCBjaGFyLCBidXQgbGFzdCBjaGFyIHdhcyBhIGxlYWRcbiAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgIH1cblxuICAgIGxlYWRTdXJyb2dhdGUgPSBudWxsXG5cbiAgICAvLyBlbmNvZGUgdXRmOFxuICAgIGlmIChjb2RlUG9pbnQgPCAweDgwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDEpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goY29kZVBvaW50KVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHg4MDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMikgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiB8IDB4QzAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDEwMDAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDMpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweEMgfCAweEUwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2ICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDExMDAwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSA0KSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHgxMiB8IDB4RjAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweEMgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY29kZSBwb2ludCcpXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGJ5dGVzXG59XG5cbmZ1bmN0aW9uIGFzY2lpVG9CeXRlcyAoc3RyKSB7XG4gIHZhciBieXRlQXJyYXkgPSBbXVxuICBmb3IgKHZhciBpID0gMDsgaSA8IHN0ci5sZW5ndGg7IGkrKykge1xuICAgIC8vIE5vZGUncyBjb2RlIHNlZW1zIHRvIGJlIGRvaW5nIHRoaXMgYW5kIG5vdCAmIDB4N0YuLlxuICAgIGJ5dGVBcnJheS5wdXNoKHN0ci5jaGFyQ29kZUF0KGkpICYgMHhGRilcbiAgfVxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIHV0ZjE2bGVUb0J5dGVzIChzdHIsIHVuaXRzKSB7XG4gIHZhciBjLCBoaSwgbG9cbiAgdmFyIGJ5dGVBcnJheSA9IFtdXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKCh1bml0cyAtPSAyKSA8IDApIGJyZWFrXG5cbiAgICBjID0gc3RyLmNoYXJDb2RlQXQoaSlcbiAgICBoaSA9IGMgPj4gOFxuICAgIGxvID0gYyAlIDI1NlxuICAgIGJ5dGVBcnJheS5wdXNoKGxvKVxuICAgIGJ5dGVBcnJheS5wdXNoKGhpKVxuICB9XG5cbiAgcmV0dXJuIGJ5dGVBcnJheVxufVxuXG5mdW5jdGlvbiBiYXNlNjRUb0J5dGVzIChzdHIpIHtcbiAgcmV0dXJuIGJhc2U2NC50b0J5dGVBcnJheShiYXNlNjRjbGVhbihzdHIpKVxufVxuXG5mdW5jdGlvbiBibGl0QnVmZmVyIChzcmMsIGRzdCwgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIGlmICgoaSArIG9mZnNldCA+PSBkc3QubGVuZ3RoKSB8fCAoaSA+PSBzcmMubGVuZ3RoKSkgYnJlYWtcbiAgICBkc3RbaSArIG9mZnNldF0gPSBzcmNbaV1cbiAgfVxuICByZXR1cm4gaVxufVxuIiwidmFyIGxvb2t1cCA9ICdBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvJztcblxuOyhmdW5jdGlvbiAoZXhwb3J0cykge1xuXHQndXNlIHN0cmljdCc7XG5cbiAgdmFyIEFyciA9ICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpXG4gICAgPyBVaW50OEFycmF5XG4gICAgOiBBcnJheVxuXG5cdHZhciBQTFVTICAgPSAnKycuY2hhckNvZGVBdCgwKVxuXHR2YXIgU0xBU0ggID0gJy8nLmNoYXJDb2RlQXQoMClcblx0dmFyIE5VTUJFUiA9ICcwJy5jaGFyQ29kZUF0KDApXG5cdHZhciBMT1dFUiAgPSAnYScuY2hhckNvZGVBdCgwKVxuXHR2YXIgVVBQRVIgID0gJ0EnLmNoYXJDb2RlQXQoMClcblx0dmFyIFBMVVNfVVJMX1NBRkUgPSAnLScuY2hhckNvZGVBdCgwKVxuXHR2YXIgU0xBU0hfVVJMX1NBRkUgPSAnXycuY2hhckNvZGVBdCgwKVxuXG5cdGZ1bmN0aW9uIGRlY29kZSAoZWx0KSB7XG5cdFx0dmFyIGNvZGUgPSBlbHQuY2hhckNvZGVBdCgwKVxuXHRcdGlmIChjb2RlID09PSBQTFVTIHx8XG5cdFx0ICAgIGNvZGUgPT09IFBMVVNfVVJMX1NBRkUpXG5cdFx0XHRyZXR1cm4gNjIgLy8gJysnXG5cdFx0aWYgKGNvZGUgPT09IFNMQVNIIHx8XG5cdFx0ICAgIGNvZGUgPT09IFNMQVNIX1VSTF9TQUZFKVxuXHRcdFx0cmV0dXJuIDYzIC8vICcvJ1xuXHRcdGlmIChjb2RlIDwgTlVNQkVSKVxuXHRcdFx0cmV0dXJuIC0xIC8vbm8gbWF0Y2hcblx0XHRpZiAoY29kZSA8IE5VTUJFUiArIDEwKVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBOVU1CRVIgKyAyNiArIDI2XG5cdFx0aWYgKGNvZGUgPCBVUFBFUiArIDI2KVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBVUFBFUlxuXHRcdGlmIChjb2RlIDwgTE9XRVIgKyAyNilcblx0XHRcdHJldHVybiBjb2RlIC0gTE9XRVIgKyAyNlxuXHR9XG5cblx0ZnVuY3Rpb24gYjY0VG9CeXRlQXJyYXkgKGI2NCkge1xuXHRcdHZhciBpLCBqLCBsLCB0bXAsIHBsYWNlSG9sZGVycywgYXJyXG5cblx0XHRpZiAoYjY0Lmxlbmd0aCAlIDQgPiAwKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgc3RyaW5nLiBMZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIDQnKVxuXHRcdH1cblxuXHRcdC8vIHRoZSBudW1iZXIgb2YgZXF1YWwgc2lnbnMgKHBsYWNlIGhvbGRlcnMpXG5cdFx0Ly8gaWYgdGhlcmUgYXJlIHR3byBwbGFjZWhvbGRlcnMsIHRoYW4gdGhlIHR3byBjaGFyYWN0ZXJzIGJlZm9yZSBpdFxuXHRcdC8vIHJlcHJlc2VudCBvbmUgYnl0ZVxuXHRcdC8vIGlmIHRoZXJlIGlzIG9ubHkgb25lLCB0aGVuIHRoZSB0aHJlZSBjaGFyYWN0ZXJzIGJlZm9yZSBpdCByZXByZXNlbnQgMiBieXRlc1xuXHRcdC8vIHRoaXMgaXMganVzdCBhIGNoZWFwIGhhY2sgdG8gbm90IGRvIGluZGV4T2YgdHdpY2Vcblx0XHR2YXIgbGVuID0gYjY0Lmxlbmd0aFxuXHRcdHBsYWNlSG9sZGVycyA9ICc9JyA9PT0gYjY0LmNoYXJBdChsZW4gLSAyKSA/IDIgOiAnPScgPT09IGI2NC5jaGFyQXQobGVuIC0gMSkgPyAxIDogMFxuXG5cdFx0Ly8gYmFzZTY0IGlzIDQvMyArIHVwIHRvIHR3byBjaGFyYWN0ZXJzIG9mIHRoZSBvcmlnaW5hbCBkYXRhXG5cdFx0YXJyID0gbmV3IEFycihiNjQubGVuZ3RoICogMyAvIDQgLSBwbGFjZUhvbGRlcnMpXG5cblx0XHQvLyBpZiB0aGVyZSBhcmUgcGxhY2Vob2xkZXJzLCBvbmx5IGdldCB1cCB0byB0aGUgbGFzdCBjb21wbGV0ZSA0IGNoYXJzXG5cdFx0bCA9IHBsYWNlSG9sZGVycyA+IDAgPyBiNjQubGVuZ3RoIC0gNCA6IGI2NC5sZW5ndGhcblxuXHRcdHZhciBMID0gMFxuXG5cdFx0ZnVuY3Rpb24gcHVzaCAodikge1xuXHRcdFx0YXJyW0wrK10gPSB2XG5cdFx0fVxuXG5cdFx0Zm9yIChpID0gMCwgaiA9IDA7IGkgPCBsOyBpICs9IDQsIGogKz0gMykge1xuXHRcdFx0dG1wID0gKGRlY29kZShiNjQuY2hhckF0KGkpKSA8PCAxOCkgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA8PCAxMikgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDIpKSA8PCA2KSB8IGRlY29kZShiNjQuY2hhckF0KGkgKyAzKSlcblx0XHRcdHB1c2goKHRtcCAmIDB4RkYwMDAwKSA+PiAxNilcblx0XHRcdHB1c2goKHRtcCAmIDB4RkYwMCkgPj4gOClcblx0XHRcdHB1c2godG1wICYgMHhGRilcblx0XHR9XG5cblx0XHRpZiAocGxhY2VIb2xkZXJzID09PSAyKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDIpIHwgKGRlY29kZShiNjQuY2hhckF0KGkgKyAxKSkgPj4gNClcblx0XHRcdHB1c2godG1wICYgMHhGRilcblx0XHR9IGVsc2UgaWYgKHBsYWNlSG9sZGVycyA9PT0gMSkge1xuXHRcdFx0dG1wID0gKGRlY29kZShiNjQuY2hhckF0KGkpKSA8PCAxMCkgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA8PCA0KSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMikpID4+IDIpXG5cdFx0XHRwdXNoKCh0bXAgPj4gOCkgJiAweEZGKVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH1cblxuXHRcdHJldHVybiBhcnJcblx0fVxuXG5cdGZ1bmN0aW9uIHVpbnQ4VG9CYXNlNjQgKHVpbnQ4KSB7XG5cdFx0dmFyIGksXG5cdFx0XHRleHRyYUJ5dGVzID0gdWludDgubGVuZ3RoICUgMywgLy8gaWYgd2UgaGF2ZSAxIGJ5dGUgbGVmdCwgcGFkIDIgYnl0ZXNcblx0XHRcdG91dHB1dCA9IFwiXCIsXG5cdFx0XHR0ZW1wLCBsZW5ndGhcblxuXHRcdGZ1bmN0aW9uIGVuY29kZSAobnVtKSB7XG5cdFx0XHRyZXR1cm4gbG9va3VwLmNoYXJBdChudW0pXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gdHJpcGxldFRvQmFzZTY0IChudW0pIHtcblx0XHRcdHJldHVybiBlbmNvZGUobnVtID4+IDE4ICYgMHgzRikgKyBlbmNvZGUobnVtID4+IDEyICYgMHgzRikgKyBlbmNvZGUobnVtID4+IDYgJiAweDNGKSArIGVuY29kZShudW0gJiAweDNGKVxuXHRcdH1cblxuXHRcdC8vIGdvIHRocm91Z2ggdGhlIGFycmF5IGV2ZXJ5IHRocmVlIGJ5dGVzLCB3ZSdsbCBkZWFsIHdpdGggdHJhaWxpbmcgc3R1ZmYgbGF0ZXJcblx0XHRmb3IgKGkgPSAwLCBsZW5ndGggPSB1aW50OC5sZW5ndGggLSBleHRyYUJ5dGVzOyBpIDwgbGVuZ3RoOyBpICs9IDMpIHtcblx0XHRcdHRlbXAgPSAodWludDhbaV0gPDwgMTYpICsgKHVpbnQ4W2kgKyAxXSA8PCA4KSArICh1aW50OFtpICsgMl0pXG5cdFx0XHRvdXRwdXQgKz0gdHJpcGxldFRvQmFzZTY0KHRlbXApXG5cdFx0fVxuXG5cdFx0Ly8gcGFkIHRoZSBlbmQgd2l0aCB6ZXJvcywgYnV0IG1ha2Ugc3VyZSB0byBub3QgZm9yZ2V0IHRoZSBleHRyYSBieXRlc1xuXHRcdHN3aXRjaCAoZXh0cmFCeXRlcykge1xuXHRcdFx0Y2FzZSAxOlxuXHRcdFx0XHR0ZW1wID0gdWludDhbdWludDgubGVuZ3RoIC0gMV1cblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSh0ZW1wID4+IDIpXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPDwgNCkgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gJz09J1xuXHRcdFx0XHRicmVha1xuXHRcdFx0Y2FzZSAyOlxuXHRcdFx0XHR0ZW1wID0gKHVpbnQ4W3VpbnQ4Lmxlbmd0aCAtIDJdIDw8IDgpICsgKHVpbnQ4W3VpbnQ4Lmxlbmd0aCAtIDFdKVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKHRlbXAgPj4gMTApXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPj4gNCkgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKCh0ZW1wIDw8IDIpICYgMHgzRilcblx0XHRcdFx0b3V0cHV0ICs9ICc9J1xuXHRcdFx0XHRicmVha1xuXHRcdH1cblxuXHRcdHJldHVybiBvdXRwdXRcblx0fVxuXG5cdGV4cG9ydHMudG9CeXRlQXJyYXkgPSBiNjRUb0J5dGVBcnJheVxuXHRleHBvcnRzLmZyb21CeXRlQXJyYXkgPSB1aW50OFRvQmFzZTY0XG59KHR5cGVvZiBleHBvcnRzID09PSAndW5kZWZpbmVkJyA/ICh0aGlzLmJhc2U2NGpzID0ge30pIDogZXhwb3J0cykpXG4iLCJleHBvcnRzLnJlYWQgPSBmdW5jdGlvbiAoYnVmZmVyLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbVxuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIG5CaXRzID0gLTdcbiAgdmFyIGkgPSBpc0xFID8gKG5CeXRlcyAtIDEpIDogMFxuICB2YXIgZCA9IGlzTEUgPyAtMSA6IDFcbiAgdmFyIHMgPSBidWZmZXJbb2Zmc2V0ICsgaV1cblxuICBpICs9IGRcblxuICBlID0gcyAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBzID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBlTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IGUgPSBlICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgbSA9IGUgJiAoKDEgPDwgKC1uQml0cykpIC0gMSlcbiAgZSA+Pj0gKC1uQml0cylcbiAgbkJpdHMgKz0gbUxlblxuICBmb3IgKDsgbkJpdHMgPiAwOyBtID0gbSAqIDI1NiArIGJ1ZmZlcltvZmZzZXQgKyBpXSwgaSArPSBkLCBuQml0cyAtPSA4KSB7fVxuXG4gIGlmIChlID09PSAwKSB7XG4gICAgZSA9IDEgLSBlQmlhc1xuICB9IGVsc2UgaWYgKGUgPT09IGVNYXgpIHtcbiAgICByZXR1cm4gbSA/IE5hTiA6ICgocyA/IC0xIDogMSkgKiBJbmZpbml0eSlcbiAgfSBlbHNlIHtcbiAgICBtID0gbSArIE1hdGgucG93KDIsIG1MZW4pXG4gICAgZSA9IGUgLSBlQmlhc1xuICB9XG4gIHJldHVybiAocyA/IC0xIDogMSkgKiBtICogTWF0aC5wb3coMiwgZSAtIG1MZW4pXG59XG5cbmV4cG9ydHMud3JpdGUgPSBmdW5jdGlvbiAoYnVmZmVyLCB2YWx1ZSwgb2Zmc2V0LCBpc0xFLCBtTGVuLCBuQnl0ZXMpIHtcbiAgdmFyIGUsIG0sIGNcbiAgdmFyIGVMZW4gPSBuQnl0ZXMgKiA4IC0gbUxlbiAtIDFcbiAgdmFyIGVNYXggPSAoMSA8PCBlTGVuKSAtIDFcbiAgdmFyIGVCaWFzID0gZU1heCA+PiAxXG4gIHZhciBydCA9IChtTGVuID09PSAyMyA/IE1hdGgucG93KDIsIC0yNCkgLSBNYXRoLnBvdygyLCAtNzcpIDogMClcbiAgdmFyIGkgPSBpc0xFID8gMCA6IChuQnl0ZXMgLSAxKVxuICB2YXIgZCA9IGlzTEUgPyAxIDogLTFcbiAgdmFyIHMgPSB2YWx1ZSA8IDAgfHwgKHZhbHVlID09PSAwICYmIDEgLyB2YWx1ZSA8IDApID8gMSA6IDBcblxuICB2YWx1ZSA9IE1hdGguYWJzKHZhbHVlKVxuXG4gIGlmIChpc05hTih2YWx1ZSkgfHwgdmFsdWUgPT09IEluZmluaXR5KSB7XG4gICAgbSA9IGlzTmFOKHZhbHVlKSA/IDEgOiAwXG4gICAgZSA9IGVNYXhcbiAgfSBlbHNlIHtcbiAgICBlID0gTWF0aC5mbG9vcihNYXRoLmxvZyh2YWx1ZSkgLyBNYXRoLkxOMilcbiAgICBpZiAodmFsdWUgKiAoYyA9IE1hdGgucG93KDIsIC1lKSkgPCAxKSB7XG4gICAgICBlLS1cbiAgICAgIGMgKj0gMlxuICAgIH1cbiAgICBpZiAoZSArIGVCaWFzID49IDEpIHtcbiAgICAgIHZhbHVlICs9IHJ0IC8gY1xuICAgIH0gZWxzZSB7XG4gICAgICB2YWx1ZSArPSBydCAqIE1hdGgucG93KDIsIDEgLSBlQmlhcylcbiAgICB9XG4gICAgaWYgKHZhbHVlICogYyA+PSAyKSB7XG4gICAgICBlKytcbiAgICAgIGMgLz0gMlxuICAgIH1cblxuICAgIGlmIChlICsgZUJpYXMgPj0gZU1heCkge1xuICAgICAgbSA9IDBcbiAgICAgIGUgPSBlTWF4XG4gICAgfSBlbHNlIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgbSA9ICh2YWx1ZSAqIGMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gZSArIGVCaWFzXG4gICAgfSBlbHNlIHtcbiAgICAgIG0gPSB2YWx1ZSAqIE1hdGgucG93KDIsIGVCaWFzIC0gMSkgKiBNYXRoLnBvdygyLCBtTGVuKVxuICAgICAgZSA9IDBcbiAgICB9XG4gIH1cblxuICBmb3IgKDsgbUxlbiA+PSA4OyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBtICYgMHhmZiwgaSArPSBkLCBtIC89IDI1NiwgbUxlbiAtPSA4KSB7fVxuXG4gIGUgPSAoZSA8PCBtTGVuKSB8IG1cbiAgZUxlbiArPSBtTGVuXG4gIGZvciAoOyBlTGVuID4gMDsgYnVmZmVyW29mZnNldCArIGldID0gZSAmIDB4ZmYsIGkgKz0gZCwgZSAvPSAyNTYsIGVMZW4gLT0gOCkge31cblxuICBidWZmZXJbb2Zmc2V0ICsgaSAtIGRdIHw9IHMgKiAxMjhcbn1cbiIsIlxuLyoqXG4gKiBpc0FycmF5XG4gKi9cblxudmFyIGlzQXJyYXkgPSBBcnJheS5pc0FycmF5O1xuXG4vKipcbiAqIHRvU3RyaW5nXG4gKi9cblxudmFyIHN0ciA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmc7XG5cbi8qKlxuICogV2hldGhlciBvciBub3QgdGhlIGdpdmVuIGB2YWxgXG4gKiBpcyBhbiBhcnJheS5cbiAqXG4gKiBleGFtcGxlOlxuICpcbiAqICAgICAgICBpc0FycmF5KFtdKTtcbiAqICAgICAgICAvLyA+IHRydWVcbiAqICAgICAgICBpc0FycmF5KGFyZ3VtZW50cyk7XG4gKiAgICAgICAgLy8gPiBmYWxzZVxuICogICAgICAgIGlzQXJyYXkoJycpO1xuICogICAgICAgIC8vID4gZmFsc2VcbiAqXG4gKiBAcGFyYW0ge21peGVkfSB2YWxcbiAqIEByZXR1cm4ge2Jvb2x9XG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBpc0FycmF5IHx8IGZ1bmN0aW9uICh2YWwpIHtcbiAgcmV0dXJuICEhIHZhbCAmJiAnW29iamVjdCBBcnJheV0nID09IHN0ci5jYWxsKHZhbCk7XG59O1xuIiwibW9kdWxlLmV4cG9ydHM9e1xuICAgIFwidmVyc2lvblwiOiBcIlwiXG59XG4iLCIvKipcbiAqIEVwaWNlbnRlciBKYXZhc2NyaXB0IGxpYnJhcmllc1xuICogdjwlPSB2ZXJzaW9uICU+XG4gKiBodHRwczovL2dpdGh1Yi5jb20vZm9yaW8vZXBpY2VudGVyLWpzLWxpYnNcbiAqL1xuXG52YXIgRiA9IHtcbiAgICB1dGlsOiB7fSxcbiAgICBmYWN0b3J5OiB7fSxcbiAgICB0cmFuc3BvcnQ6IHt9LFxuICAgIHN0b3JlOiB7fSxcbiAgICBzZXJ2aWNlOiB7fSxcbiAgICBtYW5hZ2VyOiB7XG4gICAgICAgIHN0cmF0ZWd5OiB7fVxuICAgIH0sXG5cbn07XG5cbkYudXRpbC5xdWVyeSA9IHJlcXVpcmUoJy4vdXRpbC9xdWVyeS11dGlsJyk7XG5GLnV0aWwubWFrZVNlcXVlbmNlID0gcmVxdWlyZSgnLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbkYudXRpbC5ydW4gPSByZXF1aXJlKCcuL3V0aWwvcnVuLXV0aWwnKTtcbkYudXRpbC5jbGFzc0Zyb20gPSByZXF1aXJlKCcuL3V0aWwvaW5oZXJpdCcpO1xuXG5GLmZhY3RvcnkuVHJhbnNwb3J0ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuRi50cmFuc3BvcnQuQWpheCA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0L2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcblxuRi5zZXJ2aWNlLlVSTCA9IHJlcXVpcmUoJy4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbkYuc2VydmljZS5Db25maWcgPSByZXF1aXJlKCcuL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuUnVuID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkZpbGUgPSByZXF1aXJlKCcuL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuVmFyaWFibGVzID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkRhdGEgPSByZXF1aXJlKCcuL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkF1dGggPSByZXF1aXJlKCcuL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLldvcmxkID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuU3RhdGUgPSByZXF1aXJlKCcuL3NlcnZpY2Uvc3RhdGUtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Vc2VyID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VzZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5NZW1iZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvbWVtYmVyLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuQXNzZXQgPSByZXF1aXJlKCcuL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXInKTtcblxuRi5zdG9yZS5Db29raWUgPSByZXF1aXJlKCcuL3N0b3JlL2Nvb2tpZS1zdG9yZScpO1xuRi5mYWN0b3J5LlN0b3JlID0gcmVxdWlyZSgnLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG5cbkYubWFuYWdlci5TY2VuYXJpb01hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3NjZW5hcmlvLW1hbmFnZXInKTtcbkYubWFuYWdlci5SdW5NYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9hdXRoLW1hbmFnZXInKTtcbkYubWFuYWdlci5Xb3JsZE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3dvcmxkLW1hbmFnZXInKTtcblxuRi5tYW5hZ2VyLnN0cmF0ZWd5WydhbHdheXMtbmV3J10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2Fsd2F5cy1uZXctc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnY29uZGl0aW9uYWwtY3JlYXRpb24nXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneS5pZGVudGl0eSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvaWRlbnRpdHktc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLW1pc3NpbmcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLW1pc3Npbmctc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLW1pc3NpbmcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLW1pc3Npbmctc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLXBlcnNpc3RlZCddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5Jyk7XG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ25ldy1pZi1pbml0aWFsaXplZCddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtaW5pdGlhbGl6ZWQtc3RyYXRlZ3knKTtcblxuRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyJyk7XG5GLnNlcnZpY2UuQ2hhbm5lbCA9IHJlcXVpcmUoJy4vc2VydmljZS9jaGFubmVsLXNlcnZpY2UnKTtcblxuRi52ZXJzaW9uID0gJzwlPSB2ZXJzaW9uICU+JztcbkYuYXBpID0gcmVxdWlyZSgnLi9hcGktdmVyc2lvbi5qc29uJyk7XG5cbmdsb2JhbC5GID0gRjtcbm1vZHVsZS5leHBvcnRzID0gRjtcbiIsIi8qKlxuKiAjIyBBdXRob3JpemF0aW9uIE1hbmFnZXJcbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byBtYW5hZ2UgdXNlciBhdXRoZW50aWNhdGlvbiAobG9nZ2luZyBpbiBhbmQgb3V0KSBhbmQgYXV0aG9yaXphdGlvbiAoa2VlcGluZyB0cmFjayBvZiB0b2tlbnMsIHNlc3Npb25zLCBhbmQgZ3JvdXBzKSBmb3IgcHJvamVjdHMuXG4qXG4qIFRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgaXMgbW9zdCB1c2VmdWwgZm9yIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSkgd2l0aCBhbiBhY2Nlc3MgbGV2ZWwgb2YgW0F1dGhlbnRpY2F0ZWRdKC4uLy4uLy4uL2dsb3NzYXJ5LyNhY2Nlc3MpLiBUaGVzZSBwcm9qZWN0cyBhcmUgYWNjZXNzZWQgYnkgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSB3aG8gYXJlIG1lbWJlcnMgb2Ygb25lIG9yIG1vcmUgW2dyb3Vwc10oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykuXG4qXG4qICMjIyNVc2luZyB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyXG4qXG4qIFRvIHVzZSB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdC4gVGhlbiwgbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQ6XG4qXG4qICAgICAgIHZhciBhdXRoTWdyID0gbmV3IEYubWFuYWdlci5BdXRoTWFuYWdlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB1c2VyTmFtZTogJ2VuZHVzZXIxJyxcbiogICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnXG4qICAgICAgIH0pO1xuKiAgICAgICBhdXRoTWdyLmxvZ2luKCkudGhlbihmdW5jdGlvbiAoKSB7XG4qICAgICAgICAgICBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiogICAgICAgfSk7XG4qXG4qXG4qIFRoZSBgb3B0aW9uc2Agb2JqZWN0IHBhc3NlZCB0byB0aGUgYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCBjYWxsIGNhbiBpbmNsdWRlOlxuKlxuKiAgICogYGFjY291bnRgOiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiogICAqIGB1c2VyTmFtZWA6IEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi5cbiogICAqIGBwYXNzd29yZGA6IFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGUgcHJvamVjdCB0byBsb2cgdGhpcyB1c2VyIGludG8uIE9wdGlvbmFsLlxuKiAgICogYGdyb3VwSWRgOiBJZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgZW5kIHVzZXJzIGlmIHRoZSBgcHJvamVjdGAgaXMgc3BlY2lmaWVkLlxuKlxuKiBJZiB5b3UgcHJlZmVyIHN0YXJ0aW5nIGZyb20gYSB0ZW1wbGF0ZSwgdGhlIEVwaWNlbnRlciBKUyBMaWJzIFtMb2dpbiBDb21wb25lbnRdKC4uLy4uLyNjb21wb25lbnRzKSB1c2VzIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgYXMgd2VsbC4gVGhpcyBzYW1wbGUgSFRNTCBwYWdlIChhbmQgYXNzb2NpYXRlZCBDU1MgYW5kIEpTIGZpbGVzKSBwcm92aWRlcyBhIGxvZ2luIGZvcm0gZm9yIHRlYW0gbWVtYmVycyBhbmQgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdC4gSXQgYWxzbyBpbmNsdWRlcyBhIGdyb3VwIHNlbGVjdG9yIGZvciBlbmQgdXNlcnMgdGhhdCBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBncm91cHMuXG4qL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgQXV0aEFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2F1dGgtYXBpLXNlcnZpY2UnKTtcbnZhciBNZW1iZXJBZGFwdGVyID0gcmVxdWlyZSgnLi4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBCdWZmZXIgPSByZXF1aXJlKCdidWZmZXInKS5CdWZmZXI7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogV2hlcmUgdG8gc3RvcmUgdXNlciBhY2Nlc3MgdG9rZW5zIGZvciB0ZW1wb3JhcnkgYWNjZXNzLiBEZWZhdWx0cyB0byBzdG9yaW5nIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLlxuICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICovXG4gICAgc3RvcmU6IHsgc3luY2hyb25vdXM6IHRydWUgfVxufTtcblxudmFyIEVQSV9DT09LSUVfS0VZID0ga2V5TmFtZXMuRVBJX0NPT0tJRV9LRVk7XG52YXIgRVBJX1NFU1NJT05fS0VZID0ga2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZO1xudmFyIHRva2VuO1xudmFyIHNlc3Npb247XG5cbmZ1bmN0aW9uIHNhdmVTZXNzaW9uKHVzZXJJbmZvLCBzdG9yZSkge1xuICAgIHZhciBzZXJpYWxpemVkID0gSlNPTi5zdHJpbmdpZnkodXNlckluZm8pO1xuICAgIHN0b3JlLnNldChFUElfU0VTU0lPTl9LRVksIHNlcmlhbGl6ZWQpO1xuXG4gICAgLy9qc2hpbnQgY2FtZWxjYXNlOiBmYWxzZVxuICAgIC8vanNjczpkaXNhYmxlXG4gICAgc3RvcmUuc2V0KEVQSV9DT09LSUVfS0VZLCB1c2VySW5mby5hdXRoX3Rva2VuKTtcbn1cblxuZnVuY3Rpb24gZ2V0U2Vzc2lvbihzdG9yZSkge1xuICAgIHZhciBzZXNzaW9uID0gc3RvcmUuZ2V0KEVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9JztcbiAgICByZXR1cm4gSlNPTi5wYXJzZShzZXNzaW9uKTtcbn1cblxuZnVuY3Rpb24gQXV0aE1hbmFnZXIob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2UodGhpcy5vcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIHRoaXMuaXNMb2NhbCA9IHVybENvbmZpZy5pc0xvY2FsaG9zdCgpO1xuXG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB0aGlzLm9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICAvLyBudWxsIG1pZ2h0IHNwZWNpZmllZCB0byBkaXNhYmxlIHByb2plY3QgZmlsdGVyaW5nXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wcm9qZWN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdGhpcy5zdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh0aGlzLm9wdGlvbnMuc3RvcmUpO1xuICAgIHNlc3Npb24gPSBnZXRTZXNzaW9uKHRoaXMuc3RvcmUpO1xuICAgIHRva2VuID0gdGhpcy5zdG9yZS5nZXQoRVBJX0NPT0tJRV9LRVkpIHx8ICcnO1xuICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAvL2pzY3M6ZGlzYWJsZVxuICAgIHRoaXMuYXV0aEFkYXB0ZXIgPSBuZXcgQXV0aEFkYXB0ZXIodGhpcy5vcHRpb25zLCB7IHRva2VuOiBzZXNzaW9uLmF1dGhfdG9rZW4gfSk7XG59XG5cbnZhciBfZmluZFVzZXJJbkdyb3VwID0gZnVuY3Rpb24gKG1lbWJlcnMsIGlkKSB7XG4gICAgZm9yICh2YXIgaiA9IDA7IGo8bWVtYmVycy5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAobWVtYmVyc1tqXS51c2VySWQgPT09IGlkKSB7XG4gICAgICAgICAgICByZXR1cm4gbWVtYmVyc1tqXTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgcmV0dXJuIG51bGw7XG59O1xuXG5BdXRoTWFuYWdlci5wcm90b3R5cGUgPSAkLmV4dGVuZChBdXRoTWFuYWdlci5wcm90b3R5cGUsIHtcblxuICAgIC8qKlxuICAgICogTG9ncyB1c2VyIGluLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dpbih7XG4gICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgKiAgICAgICAgICAgdXNlck5hbWU6ICdlbmR1c2VyMScsXG4gICAgKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiAgICAqICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gZXhhY3RseSBvbmUgZ3JvdXBcbiAgICAqICAgICAgICAgICAgICAgLy8gKG9yIGlmIHRoZSBsb2dpbigpIGNhbGwgaXMgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGUgZ3JvdXAgaWQpXG4gICAgKiAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIGhlcmVcbiAgICAqICAgICAgICAgICB9KVxuICAgICogICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIG11bHRpcGxlIGdyb3VwcyxcbiAgICAqICAgICAgICAgICAgICAgLy8gdGhlIGxvZ2luKCkgY2FsbCBmYWlsc1xuICAgICogICAgICAgICAgICAgICAvLyBhbmQgcmV0dXJucyBhbGwgZ3JvdXBzIG9mIHdoaWNoIHRoZSB1c2VyIGlzIGEgbWVtYmVyXG4gICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IHN0YXR1c09iai51c2VyR3JvdXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5uYW1lLCBzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5ncm91cElkKTtcbiAgICAqICAgICAgICAgICAgICAgfVxuICAgICogICAgICAgICAgIH0pO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLiBJZiBub3QgcGFzc2VkIGluIHdoZW4gY3JlYXRpbmcgYW4gaW5zdGFuY2Ugb2YgdGhlIG1hbmFnZXIgKGBGLm1hbmFnZXIuQXV0aE1hbmFnZXIoKWApLCB0aGVzZSBvcHRpb25zIHNob3VsZCBpbmNsdWRlOlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmFjY291bnRgIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnVzZXJOYW1lYCBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMucGFzc3dvcmRgIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5wcm9qZWN0YCAoT3B0aW9uYWwpIFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhlIHByb2plY3QgdG8gbG9nIHRoaXMgdXNlciBpbnRvLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpZiB0aGUgYHByb2plY3RgIGlzIHNwZWNpZmllZCBhbmQgaWYgdGhlIGVuZCB1c2VycyBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3RoZXJ3aXNlIG9wdGlvbmFsLlxuICAgICovXG4gICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AsIGVycm9yOiAkLm5vb3AgfSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuICAgICAgICB2YXIgb3V0RXJyb3IgPSBhZGFwdGVyT3B0aW9ucy5lcnJvcjtcbiAgICAgICAgdmFyIGdyb3VwSWQgPSBhZGFwdGVyT3B0aW9ucy5ncm91cElkO1xuXG4gICAgICAgIHZhciBhY2NvdW50TmFtZSA9IChvcHRpb25zICYmIG9wdGlvbnMuYWNjb3VudCkgPyBvcHRpb25zLmFjY291bnQgOiB0aGlzLm9wdGlvbnMuYWNjb3VudDtcbiAgICAgICAgdmFyIHByb2plY3ROYW1lID0gKG9wdGlvbnMgJiYgb3B0aW9ucy5wcm9qZWN0KSA/IG9wdGlvbnMucHJvamVjdCA6IHRoaXMub3B0aW9ucy5wcm9qZWN0O1xuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuc3RvcmUucm9vdCA9PT0gdW5kZWZpbmVkICYmIGFjY291bnROYW1lICYmIHByb2plY3ROYW1lKSB7XG4gICAgICAgICAgICB0aGlzLnN0b3JlLnNlcnZpY2VPcHRpb25zLnJvb3QgPSB0aGlzLmlzTG9jYWwgPyAnLycgOiAnL2FwcC8nICsgYWNjb3VudE5hbWUgKyAnLycgKyBwcm9qZWN0TmFtZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBkZWNvZGVUb2tlbiA9IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgICAgdmFyIGVuY29kZWQgPSB0b2tlbi5zcGxpdCgnLicpWzFdO1xuICAgICAgICAgICAgd2hpbGUgKGVuY29kZWQubGVuZ3RoICUgNCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIGVuY29kZWQgKz0gJz0nO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZGVjb2RlID0gd2luZG93LmF0b2IgPyB3aW5kb3cuYXRvYiA6IGZ1bmN0aW9uIChlbmNvZGVkKSB7IHJldHVybiBuZXcgQnVmZmVyKGVuY29kZWQsICdiYXNlNjQnKS50b1N0cmluZygnYXNjaWknKTsgfTtcblxuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGVjb2RlKGVuY29kZWQpKTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgaGFuZGxlR3JvdXBFcnJvciA9IGZ1bmN0aW9uIChtZXNzYWdlLCBzdGF0dXNDb2RlLCBkYXRhKSB7XG4gICAgICAgICAgICAvLyBsb2dvdXQgdGhlIHVzZXIgc2luY2UgaXQncyBpbiBhbiBpbnZhbGlkIHN0YXRlIHdpdGggbm8gZ3JvdXAgc2VsZWN0ZWRcbiAgICAgICAgICAgIF90aGlzLmxvZ291dCgpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBlcnJvciA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkYXRhLCB7IHN0YXR1c1RleHQ6IG1lc3NhZ2UsIHN0YXR1czogc3RhdHVzQ29kZSB9KTtcbiAgICAgICAgICAgICAgICAkZC5yZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZVN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAgICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgICAgICB0b2tlbiA9IHJlc3BvbnNlLmFjY2Vzc190b2tlbjtcbiAgICAgICAgICAgIHZhciB1c2VySW5mbyA9IGRlY29kZVRva2VuKHRva2VuKTtcbiAgICAgICAgICAgIHZhciB1c2VyR3JvdXBPcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIGFkYXB0ZXJPcHRpb25zLCB7IHN1Y2Nlc3M6ICQubm9vcCwgdG9rZW46IHRva2VuIH0pO1xuICAgICAgICAgICAgX3RoaXMuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogdXNlckluZm8udXNlcl9pZCwgdG9rZW46IHRva2VuIH0sIHVzZXJHcm91cE9wdHMpLmRvbmUoIGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGEgPSB7YXV0aDogcmVzcG9uc2UsIHVzZXI6IHVzZXJJbmZvLCB1c2VyR3JvdXBzOiBtZW1iZXJJbmZvLCBncm91cFNlbGVjdGlvbjoge30gfTtcblxuICAgICAgICAgICAgICAgIHZhciBzZXNzaW9uSW5mbyA9IHtcbiAgICAgICAgICAgICAgICAgICAgJ2F1dGhfdG9rZW4nOiB0b2tlbixcbiAgICAgICAgICAgICAgICAgICAgJ2FjY291bnQnOiBhZGFwdGVyT3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgICAgICAncHJvamVjdCc6IGFkYXB0ZXJPcHRpb25zLnByb2plY3QsXG4gICAgICAgICAgICAgICAgICAgICd1c2VySWQnOiB1c2VySW5mby51c2VyX2lkXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAvLyBUaGUgZ3JvdXAgaXMgbm90IHJlcXVpcmVkIGlmIHRoZSB1c2VyIGlzIG5vdCBsb2dnaW5nIGludG8gYSBwcm9qZWN0XG4gICAgICAgICAgICAgICAgaWYgKCFhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHNhdmVTZXNzaW9uKHNlc3Npb25JbmZvLCBfdGhpcy5zdG9yZSk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBncm91cCA9IG51bGw7XG4gICAgICAgICAgICAgICAgaWYgKG1lbWJlckluZm8ubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoZSB1c2VyIGhhcyBubyBncm91cHMgYXNzb2NpYXRlZCBpbiB0aGlzIGFjY291bnQnLCA0MDEsIGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZW1iZXJJbmZvLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTZWxlY3QgdGhlIG9ubHkgZ3JvdXBcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBtZW1iZXJJbmZvWzBdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobWVtYmVySW5mby5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChncm91cElkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmlsdGVyZWRHcm91cHMgPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKHJlc0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc0dyb3VwLmdyb3VwSWQgPT09IGdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gZmlsdGVyZWRHcm91cHMubGVuZ3RoID09PSAxID8gZmlsdGVyZWRHcm91cHNbMF0gOiBudWxsO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBncm91cFNlbGVjdGlvbiA9IGdyb3VwLmdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEuZ3JvdXBTZWxlY3Rpb25bYWRhcHRlck9wdGlvbnMucHJvamVjdF0gPSBncm91cFNlbGVjdGlvbjtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNlc3Npb25JbmZvV2l0aEdyb3VwID0gJC5leHRlbmQoe30sIHNlc3Npb25JbmZvLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAnZ3JvdXBJZCc6IGdyb3VwLmdyb3VwSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAnZ3JvdXBOYW1lJzogZ3JvdXAubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICdpc0ZhYyc6IF9maW5kVXNlckluR3JvdXAoZ3JvdXAubWVtYmVycywgdXNlckluZm8udXNlcl9pZCkucm9sZSA9PT0gJ2ZhY2lsaXRhdG9yJ1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgc2F2ZVNlc3Npb24oc2Vzc2lvbkluZm9XaXRoR3JvdXAsIF90aGlzLnN0b3JlKTtcbiAgICAgICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoaXMgdXNlciBpcyBhc3NvY2lhdGVkIHdpdGggbW9yZSB0aGFuIG9uZSBncm91cC4gUGxlYXNlIHNwZWNpZnkgYSBncm91cCBpZCB0byBsb2cgaW50byBhbmQgdHJ5IGFnYWluJywgNDAzLCBkYXRhKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGhhbmRsZVN1Y2Nlc3M7XG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vIFRyeSB0byBsb2dpbiBhcyBhIHN5c3RlbSB1c2VyXG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuYWNjb3VudCA9IG51bGw7XG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuZXJyb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdChyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIF90aGlzLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuYXV0aEFkYXB0ZXIubG9naW4oYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAqIExvZ3MgdXNlciBvdXQuXG4gICAgKlxuICAgICogKipFeGFtcGxlKipcbiAgICAqXG4gICAgKiAgICAgICBhdXRoTWdyLmxvZ291dCgpO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICovXG4gICAgbG9nb3V0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgYWRhcHRlck9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHRva2VuOiB0b2tlbiB9LCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciByZW1vdmVDb29raWVGbiA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgX3RoaXMuc3RvcmUucmVtb3ZlKEVQSV9DT09LSUVfS0VZLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICBfdGhpcy5zdG9yZS5yZW1vdmUoRVBJX1NFU1NJT05fS0VZLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICB0b2tlbiA9ICcnO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhBZGFwdGVyLmxvZ291dChhZGFwdGVyT3B0aW9ucykuZG9uZShyZW1vdmVDb29raWVGbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGV4aXN0aW5nIHVzZXIgYWNjZXNzIHRva2VuIGlmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluLiBPdGhlcndpc2UsIGxvZ3MgdGhlIHVzZXIgaW4sIGNyZWF0aW5nIGEgbmV3IHVzZXIgYWNjZXNzIHRva2VuLCBhbmQgcmV0dXJucyB0aGUgbmV3IHRva2VuLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBhdXRoTWdyLmdldFRva2VuKClcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coJ015IHRva2VuIGlzICcsIHRva2VuKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgaWYgKHRva2VuKSB7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKHRva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICogICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKylcbiAgICAgKiAgICAgICAgICAgICAgICAgIHsgY29uc29sZS5sb2coZ3JvdXBzW2ldLm5hbWUpOyB9XG4gICAgICogICAgICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIHBhcnRpY3VsYXIgdXNlclxuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHt1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB0b2tlbjogc2F2ZWRQcm9qQWNjZXNzVG9rZW4gfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcGFyYW1zYCBPYmplY3Qgd2l0aCBhIHVzZXJJZCBhbmQgdG9rZW4gcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSB1c2VySWQuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBPdGhlcndpc2UsIHBhc3MgYSBzdHJpbmcuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGBwYXJhbXMudG9rZW5gIFRoZSBhdXRob3JpemF0aW9uIGNyZWRlbnRpYWxzIChhY2Nlc3MgdG9rZW4pIHRvIHVzZSBmb3IgY2hlY2tpbmcgdGhlIGdyb3VwcyBmb3IgdGhpcyB1c2VyLiBJZiBsb29raW5nIHVwIGdyb3VwcyBmb3IgdGhlIGN1cnJlbnRseSBsb2dnZWQgaW4gdXNlciwgdGhpcyBpcyBpbiB0aGUgc2Vzc2lvbiBpbmZvcm1hdGlvbi4gQSB0ZWFtIG1lbWJlcidzIHRva2VuIG9yIGEgcHJvamVjdCBhY2Nlc3MgdG9rZW4gY2FuIGFjY2VzcyBhbGwgdGhlIGdyb3VwcyBmb3IgYWxsIGVuZCB1c2VycyBpbiB0aGUgdGVhbSBvciBwcm9qZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKi9cbiAgICBnZXRVc2VyR3JvdXBzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHsgc3VjY2VzczogJC5ub29wIH0sIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAobWVtYmVySW5mbykge1xuICAgICAgICAgICAgLy8gVGhlIG1lbWJlciBBUEkgaXMgYXQgdGhlIGFjY291bnQgc2NvcGUsIHdlIGZpbHRlciBieSBwcm9qZWN0XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICAgICAgICAgIG1lbWJlckluZm8gPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBncm91cC5wcm9qZWN0ID09PSBhZGFwdGVyT3B0aW9ucy5wcm9qZWN0O1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRTdWNjZXNzLmFwcGx5KHRoaXMsIFttZW1iZXJJbmZvXSk7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKG1lbWJlckluZm8pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBtZW1iZXJBZGFwdGVyID0gbmV3IE1lbWJlckFkYXB0ZXIoeyB0b2tlbjogcGFyYW1zLnRva2VuIH0pO1xuICAgICAgICBtZW1iZXJBZGFwdGVyLmdldEdyb3Vwc0ZvclVzZXIocGFyYW1zLCBhZGFwdGVyT3B0aW9ucykuZmFpbCgkZC5yZWplY3QpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHNlc3Npb24gaW5mb3JtYXRpb24gZm9yIHRoZSBjdXJyZW50IHVzZXIsIGluY2x1ZGluZyB0aGUgYHVzZXJJZGAsIGBhY2NvdW50YCwgYHByb2plY3RgLCBgZ3JvdXBJZGAsIGBncm91cE5hbWVgLCBgaXNGYWNgICh3aGV0aGVyIHRoZSBlbmQgdXNlciBpcyBhIGZhY2lsaXRhdG9yIG9mIHRoaXMgZ3JvdXApLCBhbmQgYGF1dGhfdG9rZW5gICh1c2VyIGFjY2VzcyB0b2tlbikuXG4gICAgICpcbiAgICAgKiAqSW1wb3J0YW50KjogVGhpcyBtZXRob2QgaXMgc3luY2hyb25vdXMuIFRoZSBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHJldHVybmVkIGltbWVkaWF0ZWx5IGluIGFuIG9iamVjdDsgbm8gY2FsbGJhY2tzIG9yIHByb21pc2VzIGFyZSBuZWVkZWQuXG4gICAgICpcbiAgICAgKiBCeSBkZWZhdWx0LCBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHN0b3JlZCBpbiBhIGNvb2tpZSBpbiB0aGUgYnJvd3Nlci4gWW91IGNhbiBjaGFuZ2UgdGhpcyB3aXRoIHRoZSBgc3RvcmVgIGNvbmZpZ3VyYXRpb24gb3B0aW9uLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm86IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiBnZXRTZXNzaW9uKHRoaXMuc3RvcmUsIG9wdGlvbnMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEF1dGhNYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2hhbm5lbCA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlJyk7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgYXJvdW5kIHRoZSBkZWZhdWx0IFtjb21ldGQgSmF2YVNjcmlwdCBsaWJyYXJ5XShodHRwOi8vZG9jcy5jb21ldGQub3JnLzIvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCksIGAkLmNvbWV0ZGAuIEl0IHByb3ZpZGVzIGEgZmV3IG5pY2UgZmVhdHVyZXMgdGhhdCBgJC5jb21ldGRgIGRvZXNuJ3QsIGluY2x1ZGluZzpcbiAqXG4gKiAqIEF1dG9tYXRpYyByZS1zdWJzY3JpcHRpb24gdG8gY2hhbm5lbHMgaWYgeW91IGxvc2UgeW91ciBjb25uZWN0aW9uXG4gKiAqIE9ubGluZSAvIE9mZmxpbmUgbm90aWZpY2F0aW9uc1xuICogKiAnRXZlbnRzJyBmb3IgY29tZXRkIG5vdGlmaWNhdGlvbnMgKGluc3RlYWQgb2YgaGF2aW5nIHRvIGxpc3RlbiBvbiBzcGVjaWZpYyBtZXRhIGNoYW5uZWxzKVxuICpcbiAqIFdoaWxlIHlvdSBjYW4gd29yayBkaXJlY3RseSB3aXRoIHRoZSBDaGFubmVsIE1hbmFnZXIgdGhyb3VnaCBOb2RlLmpzIChmb3IgZXhhbXBsZSwgYHJlcXVpcmUoJ21hbmFnZXIvY2hhbm5lbC1tYW5hZ2VyJylgKSAtLSBvciBldmVuIHdvcmsgZGlyZWN0bHkgd2l0aCBgJC5jb21ldGRgIGFuZCBFcGljZW50ZXIncyB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIC0tIG1vc3Qgb2Z0ZW4gaXQgd2lsbCBiZSBlYXNpZXN0IHRvIHdvcmsgd2l0aCB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKS4gVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIHRoYXQgaW5zdGFudGlhdGVzIGEgQ2hhbm5lbCBNYW5hZ2VyIHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgTWFuYWdlci4gKFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLilcbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgTWFuYWdlciBpbiBjbGllbnQtc2lkZSBKYXZhU2NyaXB0LCBpbnN0YW50aWF0ZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSwgZ2V0IHRoZSBjaGFubmVsLCB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gKlxuICogICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAqICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgTWFuYWdlci4gQmVzaWRlcyB0aGUgY29tbW9uIG9wdGlvbnMgbGlzdGVkIGhlcmUsIHNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIG90aGVyIHN1cHBvcnRlZCBvcHRpb25zLlxuICogKiBgb3B0aW9ucy51cmxgIFRoZSBDb21ldGQgZW5kcG9pbnQgVVJMLlxuICogKiBgb3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkYCBXaGV0aGVyIHdlYnNvY2tldCBzdXBwb3J0IGlzIGFjdGl2ZSAoYm9vbGVhbikuXG4gKiAqIGBvcHRpb25zLmNoYW5uZWxgIE90aGVyIGRlZmF1bHRzIHRvIHBhc3Mgb24gdG8gaW5zdGFuY2VzIG9mIHRoZSB1bmRlcmx5aW5nIENoYW5uZWwgU2VydmljZS4gU2VlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pIGZvciBkZXRhaWxzLlxuICpcbiAqL1xudmFyIENoYW5uZWxNYW5hZ2VyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICBpZiAoISQuY29tZXRkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tZXRkIGxpYnJhcnkgbm90IGZvdW5kLiBQbGVhc2UgaW5jbHVkZSBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy51cmwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhbiB1cmwgZm9yIHRoZSBjb21ldGQgc2VydmVyJyk7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbG9nIGxldmVsIGZvciB0aGUgY2hhbm5lbCAobG9ncyB0byBjb25zb2xlKS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGxvZ0xldmVsOiAnaW5mbycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlLiBEZWZhdWx0cyB0byBgZmFsc2VgOyBFcGljZW50ZXIgZG9lc24ndCBjdXJyZW50bHkgc3VwcG9ydCBjb21tdW5pY2F0aW9uIHRocm91Z2ggd2Vic29ja2V0cy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICB3ZWJzb2NrZXRFbmFibGVkOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogSWYgZmFsc2UgZWFjaCBpbnN0YW5jZSBvZiBDaGFubmVsIHdpbGwgaGF2ZSBhIHNlcGFyYXRlIGNvbWV0ZCBjb25uZWN0aW9uIHRvIHNlcnZlciwgd2hpY2ggY291bGQgYmUgbm9pc3kuIFNldCB0byB0cnVlIHRvIHJlLXVzZSB0aGUgc2FtZSBjb25uZWN0aW9uIGFjcm9zcyBpbnN0YW5jZXMuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2hhcmVDb25uZWN0aW9uOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLyksIHdoaWNoIGFyZSBjcmVhdGVkIHRocm91Z2ggYGdldENoYW5uZWwoKWAuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBjaGFubmVsOiB7XG5cbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMgPSBbXTtcbiAgICB0aGlzLm9wdGlvbnMgPSBkZWZhdWx0Q29tZXRPcHRpb25zO1xuXG4gICAgaWYgKGRlZmF1bHRDb21ldE9wdGlvbnMuc2hhcmVDb25uZWN0aW9uICYmIENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkKSB7XG4gICAgICAgIHRoaXMuY29tZXRkID0gQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQ7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICB2YXIgY29tZXRkID0gbmV3ICQuQ29tZXRkKCk7XG4gICAgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQgPSBjb21ldGQ7XG5cbiAgICBjb21ldGQud2Vic29ja2V0RW5hYmxlZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMud2Vic29ja2V0RW5hYmxlZDtcblxuICAgIHRoaXMuaXNDb25uZWN0ZWQgPSBmYWxzZTtcbiAgICB2YXIgY29ubmVjdGlvbkJyb2tlbiA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignZGlzY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIGNvbm5lY3Rpb25TdWNjZWVkZWQgPSBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIoJ2Nvbm5lY3QnLCBtZXNzYWdlKTtcbiAgICB9O1xuICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICBjb21ldGQuY29uZmlndXJlKGRlZmF1bHRDb21ldE9wdGlvbnMpO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9jb25uZWN0JywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgdmFyIHdhc0Nvbm5lY3RlZCA9IHRoaXMuaXNDb25uZWN0ZWQ7XG4gICAgICAgIHRoaXMuaXNDb25uZWN0ZWQgPSAobWVzc2FnZS5zdWNjZXNzZnVsID09PSB0cnVlKTtcbiAgICAgICAgaWYgKCF3YXNDb25uZWN0ZWQgJiYgdGhpcy5pc0Nvbm5lY3RlZCkgeyAvL0Nvbm5lY3RpbmcgZm9yIHRoZSBmaXJzdCB0aW1lXG4gICAgICAgICAgICBjb25uZWN0aW9uU3VjY2VlZGVkLmNhbGwodGhpcywgbWVzc2FnZSk7XG4gICAgICAgIH0gZWxzZSBpZiAod2FzQ29ubmVjdGVkICYmICF0aGlzLmlzQ29ubmVjdGVkKSB7IC8vT25seSB0aHJvdyBkaXNjb25uZWN0ZWQgbWVzc2FnZSBmcm8gdGhlIGZpcnN0IGRpc2Nvbm5lY3QsIG5vdCBvbmNlIHBlciB0cnlcbiAgICAgICAgICAgIGNvbm5lY3Rpb25Ccm9rZW4uY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH0uYmluZCh0aGlzKSk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Rpc2Nvbm5lY3QnLCBjb25uZWN0aW9uQnJva2VuKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvaGFuZHNoYWtlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgaWYgKG1lc3NhZ2Uuc3VjY2Vzc2Z1bCkge1xuICAgICAgICAgICAgLy9odHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0X3N1YnNjcmliZS5odG1sI2phdmFzY3JpcHRfc3Vic2NyaWJlX21ldGFfY2hhbm5lbHNcbiAgICAgICAgICAgIC8vIF4gXCJkeW5hbWljIHN1YnNjcmlwdGlvbnMgYXJlIGNsZWFyZWQgKGxpa2UgYW55IG90aGVyIHN1YnNjcmlwdGlvbikgYW5kIHRoZSBhcHBsaWNhdGlvbiBuZWVkcyB0byBmaWd1cmUgb3V0IHdoaWNoIGR5bmFtaWMgc3Vic2NyaXB0aW9uIG11c3QgYmUgcGVyZm9ybWVkIGFnYWluXCJcbiAgICAgICAgICAgIGNvbWV0ZC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgJChtZS5jdXJyZW50U3Vic2NyaXB0aW9ucykuZWFjaChmdW5jdGlvbiAoaW5kZXgsIHN1YnMpIHtcbiAgICAgICAgICAgICAgICAgICAgY29tZXRkLnJlc3Vic2NyaWJlKHN1YnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vT3RoZXIgaW50ZXJlc3RpbmcgZXZlbnRzIGZvciByZWZlcmVuY2VcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3N1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3N1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWJzY3JpYmUnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCd1bnN1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvcHVibGlzaCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3B1Ymxpc2gnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3Vuc3VjY2Vzc2Z1bCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ2Vycm9yJywgbWVzc2FnZSk7XG4gICAgfSk7XG5cbiAgICBjb21ldGQuaGFuZHNoYWtlKCk7XG5cbiAgICB0aGlzLmNvbWV0ZCA9IGNvbWV0ZDtcbn07XG5cblxuQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgIHZhciBjaGFubmVsID0gY20uZ2V0Q2hhbm5lbCgpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvL0lmIHlvdSBqdXN0IHdhbnQgdG8gcGFzcyBpbiBhIHN0cmluZ1xuICAgICAgICBpZiAob3B0aW9ucyAmJiAhJC5pc1BsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAgICAgdHJhbnNwb3J0OiB0aGlzLmNvbWV0ZFxuICAgICAgICB9O1xuICAgICAgICB2YXIgY2hhbm5lbCA9IG5ldyBDaGFubmVsKCQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLm9wdGlvbnMuY2hhbm5lbCwgZGVmYXVsdHMsIG9wdGlvbnMpKTtcblxuXG4gICAgICAgIC8vV3JhcCBzdWJzIGFuZCB1bnN1YnMgc28gd2UgY2FuIHVzZSBpdCB0byByZS1hdHRhY2ggaGFuZGxlcnMgYWZ0ZXIgYmVpbmcgZGlzY29ubmVjdGVkXG4gICAgICAgIHZhciBzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHN1YmlkID0gc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyAgPSB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmNvbmNhdChzdWJpZCk7XG4gICAgICAgICAgICByZXR1cm4gc3ViaWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuXG4gICAgICAgIHZhciB1bnN1YnMgPSBjaGFubmVsLnVuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnVuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJlbW92ZWQgPSB1bnN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zW2ldLmlkID09PSByZW1vdmVkLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZW1vdmVkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlclxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIChtb3JlIGdlbmVyaWMpIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pLCB0byBpbnN0YW50aWF0ZSBpdCB3aXRoIEVwaWNlbnRlci1zcGVjaWZpYyBkZWZhdWx0cy4gSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGluY2x1ZGluZyBhIG5vdGlmaWNhdGlvbiBvciBjaGF0IGZlYXR1cmUgaW4geW91ciBwcm9qZWN0LCB1c2luZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIHByb2JhYmx5IHRoZSBlYXNpZXN0IHdheSB0byBnZXQgc3RhcnRlZC5cbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXI6IGluc3RhbnRpYXRlIGl0LCBnZXQgdGhlIGNoYW5uZWwgb2YgdGhlIHNjb3BlIHlvdSB3YW50IChbdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLCBvciBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpKSwgdGhlbiB1c2UgdGhlIGNoYW5uZWwncyBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIHN1YnNjcmliZSB0byB0b3BpY3Mgb3IgcHVibGlzaCBkYXRhIHRvIHRvcGljcy5cbiAqXG4gKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAqXG4gKiBGb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIEVwaWNlbnRlcidzIHB1c2ggY2hhbm5lbCwgc2VlIHRoZSBpbnRyb2R1Y3Rvcnkgbm90ZXMgb24gdGhlIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIHBhZ2UuXG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYHNlcnZlcmAgT2JqZWN0IHdpdGggZGV0YWlscyBhYm91dCB0aGUgRXBpY2VudGVyIHByb2plY3QgZm9yIHRoaXMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbnN0YW5jZS5cbiAqICogYHNlcnZlci5hY2NvdW50YCBUaGUgRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgc2VydmVyLnByb2plY3RgIEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICovXG5cbnZhciBDaGFubmVsTWFuYWdlciA9IHJlcXVpcmUoJy4vY2hhbm5lbC1tYW5hZ2VyJyk7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgdXJsU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlJyk7XG5cbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBzZXNzaW9uID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG52YXIgZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvciA9IGZ1bmN0aW9uICh2YWx1ZSwgc2Vzc2lvbktleU5hbWUsIHNldHRpbmdzKSB7XG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgaWYgKHNldHRpbmdzICYmIHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXSkge1xuICAgICAgICAgICAgdmFsdWUgPSBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV07XG4gICAgICAgIH0gZWxzZSBpZiAodXNlckluZm9bc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHVzZXJJbmZvW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihzZXNzaW9uS2V5TmFtZSArICcgbm90IGZvdW5kLiBQbGVhc2UgbG9nLWluIGFnYWluLCBvciBzcGVjaWZ5ICcgKyBzZXNzaW9uS2V5TmFtZSArICcgZXhwbGljaXRseScpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbn07XG52YXIgX19zdXBlciA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZTtcbnZhciBFcGljZW50ZXJDaGFubmVsTWFuYWdlciA9IGNsYXNzRnJvbShDaGFubmVsTWFuYWdlciwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcblxuICAgICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgICAgICBhY2NvdW50OiB1c2VySW5mby5hY2NvdW50LFxuICAgICAgICAgICAgcHJvamVjdDogdXNlckluZm8ucHJvamVjdCxcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIHVzZXJJbmZvLCBvcHRpb25zKTtcblxuICAgICAgICB2YXIgdXJsT3B0cyA9IHVybFNlcnZpY2UoZGVmYXVsdENvbWV0T3B0aW9ucy5zZXJ2ZXIpO1xuICAgICAgICBpZiAoIWRlZmF1bHRDb21ldE9wdGlvbnMudXJsKSB7XG4gICAgICAgICAgICAvL0RlZmF1bHQgZXBpY2VudGVyIGNvbWV0ZCBlbmRwb2ludFxuICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy51cmwgPSB1cmxPcHRzLnByb3RvY29sICsgJzovLycgKyB1cmxPcHRzLmhvc3QgKyAnL2NoYW5uZWwvc3Vic2NyaWJlJztcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgZGVmYXVsdENvbWV0T3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBnaXZlbiBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLiBUaGUgZ3JvdXAgbXVzdCBleGlzdCBpbiB0aGUgYWNjb3VudCAodGVhbSkgYW5kIHByb2plY3QgcHJvdmlkZWQuXG4gICAgICpcbiAgICAgKiBUaGVyZSBhcmUgbm8gbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWw7IGFsbCBtZXNzYWdlcyBhcmUgdXNlci1vcmlnaW5hdGVkLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJ2Jyb2FkY2FzdHMnLCBjYWxsYmFjayk7XG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBHcm91cCB0byBicm9hZGNhc3QgdG8uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldEdyb3VwQ2hhbm5lbDogZnVuY3Rpb24gKGdyb3VwTmFtZSkge1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScpO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2dyb3VwJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lXS5qb2luKCcvJyk7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICogICAgICAgICBydW46IHsgbW9kZWw6ICdtb2RlbC5lcW4nIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICogICAgIHdvcmxkTWFuYWdlci5nZXRDdXJyZW50V29ybGQoKS50aGVuKGZ1bmN0aW9uICh3b3JsZE9iamVjdCwgd29ybGRBZGFwdGVyKSB7XG4gICAgICogICAgICAgICB2YXIgd29ybGRDaGFubmVsID0gY20uZ2V0V29ybGRDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHdvcmxkQ2hhbm5lbC5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICogICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICogICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFRoZSB3b3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFdvcmxkQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCBncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHdvcmxkaWQgPSAoJC5pc1BsYWluT2JqZWN0KHdvcmxkKSAmJiB3b3JsZC5pZCkgPyB3b3JsZC5pZCA6IHdvcmxkO1xuICAgICAgICBpZiAoIXdvcmxkaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgYSB3b3JsZCBpZCcpO1xuICAgICAgICB9XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJyk7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvd29ybGQnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgY3VycmVudCBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaW4gdGhhdCB1c2VyJ3MgY3VycmVudCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS4gTm90ZSB0aGF0IHRoaXMgY2hhbm5lbCBvbmx5IGdldHMgbm90aWZpY2F0aW9ucyBmb3Igd29ybGRzIGN1cnJlbnRseSBpbiBtZW1vcnkuIChTZWUgbW9yZSBiYWNrZ3JvdW5kIG9uIFtwZXJzaXN0ZW5jZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlKS4pXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB1c2VyQ2hhbm5lbCA9IGNtLmdldFVzZXJDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHVzZXJDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFVzZXJDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXIsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVzZXJpZCA9ICgkLmlzUGxhaW5PYmplY3QodXNlcikgJiYgdXNlci5pZCkgPyB1c2VyLmlkIDogdXNlcjtcbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkLCB1c2VyaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIHRoYXQgYXV0b21hdGljYWxseSB0cmFja3MgdGhlIHByZXNlbmNlIG9mIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhhdCBpcywgd2hldGhlciB0aGUgZW5kIHVzZXIgaXMgY3VycmVudGx5IG9ubGluZSBpbiB0aGlzIGdyb3VwIGFuZCB3b3JsZC4gTm90aWZpY2F0aW9ucyBhcmUgYXV0b21hdGljYWxseSBzZW50IHdoZW4gdGhlIGVuZCB1c2VyIGNvbWVzIG9ubGluZSwgYW5kIHdoZW4gdGhlIGVuZCB1c2VyIGdvZXMgb2ZmbGluZSAobm90IHByZXNlbnQgZm9yIG1vcmUgdGhhbiAyIG1pbnV0ZXMpLiBVc2VmdWwgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZm9yIGxldHRpbmcgZWFjaCBlbmQgdXNlciBrbm93IHdoZXRoZXIgb3RoZXIgdXNlcnMgaW4gdGhlaXIgc2hhcmVkIHdvcmxkIGFyZSBhbHNvIG9ubGluZS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIG1vZGVsOiAnbW9kZWwuZXFuJ1xuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZFNlcnZpY2UpIHtcbiAgICAgKiAgICAgICAgIHZhciBwcmVzZW5jZUNoYW5uZWwgPSBjbS5nZXRQcmVzZW5jZUNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgcHJlc2VuY2VDaGFubmVsLm9uKCdwcmVzZW5jZScsIGZ1bmN0aW9uIChldnQsIG5vdGlmaWNhdGlvbikge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZyhub3RpZmljYXRpb24ub25saW5lLCBub3RpZmljYXRpb24udXNlcklkKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB3b3JsZGAgV29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB1c2VyaWRgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFByZXNlbmNlQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCB1c2VyaWQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgdmFyIGxhc3RQaW5nVGltZSA9IHsgfTtcblxuICAgICAgICB2YXIgUElOR19JTlRFUlZBTCA9IDYwMDA7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCdpbnRlcm5hbC1waW5nLWNoYW5uZWwnLCBmdW5jdGlvbiAobm90aWZpY2F0aW9uKSB7XG4gICAgICAgICAgICB2YXIgaW5jb21pbmdVc2VySWQgPSBub3RpZmljYXRpb24uZGF0YS51c2VyO1xuICAgICAgICAgICAgaWYgKCFsYXN0UGluZ1RpbWVbaW5jb21pbmdVc2VySWRdICYmIGluY29taW5nVXNlcklkICE9PSB1c2VyaWQpIHtcbiAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDogaW5jb21pbmdVc2VySWQsIG9ubGluZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIHsgdXNlcjogdXNlcmlkIH0pO1xuXG4gICAgICAgICAgICAkLmVhY2gobGFzdFBpbmdUaW1lLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBub3cgPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSAmJiB2YWx1ZSArIChQSU5HX0lOVEVSVkFMICogMikgPCBub3cpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2tleV0gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDoga2V5LCBvbmxpbmU6IGZhbHNlIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBQSU5HX0lOVEVSVkFMKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIGNvbGxlY3Rpb24uIChUaGUgY29sbGVjdGlvbiBuYW1lIGlzIHNwZWNpZmllZCBpbiB0aGUgYHJvb3RgIGFyZ3VtZW50IHdoZW4gdGhlIFtEYXRhIFNlcnZpY2VdKC4uL2RhdGEtYXBpLXNlcnZpY2UvKSBpcyBpbnN0YW50aWF0ZWQuKSBNdXN0IGJlIG9uZSBvZiB0aGUgY29sbGVjdGlvbnMgaW4gdGhpcyBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBhdXRvbWF0aWMgbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWwgd2hlbiBkYXRhIGlzIGNyZWF0ZWQsIHVwZGF0ZWQsIG9yIGRlbGV0ZWQgaW4gdGhpcyBjb2xsZWN0aW9uLiBTZWUgbW9yZSBvbiBbYXV0b21hdGljIG1lc3NhZ2VzIHRvIHRoZSBkYXRhIGNoYW5uZWxdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNkYXRhLW1lc3NhZ2VzKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZ2MgPSBjbS5nZXREYXRhQ2hhbm5lbCgnc3VydmV5LXJlc3BvbnNlcycpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEsIG1ldGEpIHtcbiAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIG1ldGEuZGF0ZSBpcyB0aW1lIG9mIGNoYW5nZSxcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnN1YlR5cGUgaXMgdGhlIGtpbmQgb2YgY2hhbmdlOiBuZXcsIHVwZGF0ZSwgb3IgZGVsZXRlXG4gICAgICogICAgICAgICAgLy8gbWV0YS5wYXRoIGlzIHRoZSBmdWxsIHBhdGggdG8gdGhlIGNoYW5nZWQgZGF0YVxuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKG1ldGEpO1xuICAgICAqICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgY29sbGVjdGlvbmAgTmFtZSBvZiBjb2xsZWN0aW9uIHdob3NlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIHlvdSB3YW50IHRvIHJlY2VpdmUuXG4gICAgICovXG4gICAgZ2V0RGF0YUNoYW5uZWw6IGZ1bmN0aW9uIChjb2xsZWN0aW9uKSB7XG4gICAgICAgIGlmICghY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIGNvbGxlY3Rpb24gdG8gbGlzdGVuIG9uLicpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2RhdGEnLCBhY2NvdW50LCBwcm9qZWN0LCBjb2xsZWN0aW9uXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgLy9UT0RPOiBGaXggYWZ0ZXIgRXBpY2VudGVyIGJ1ZyBpcyByZXNvbHZlZFxuICAgICAgICB2YXIgb2xkc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjYWxsYmFja1dpdGhDbGVhbkRhdGEgPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgICAgICAgICAgICAgIHZhciBtZXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYXlsb2FkLmNoYW5uZWwsXG4gICAgICAgICAgICAgICAgICAgIHN1YlR5cGU6IHBheWxvYWQuZGF0YS5zdWJUeXBlLFxuICAgICAgICAgICAgICAgICAgICBkYXRlOiBwYXlsb2FkLmRhdGEuZGF0ZVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGFjdHVhbERhdGEgPSBwYXlsb2FkLmRhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICBpZiAoYWN0dWFsRGF0YS5kYXRhKSB7IC8vRGVsZXRlIG5vdGlmaWNhdGlvbnMgYXJlIG9uZSBkYXRhLWxldmVsIGJlaGluZCBvZiBjb3Vyc2VcbiAgICAgICAgICAgICAgICAgICAgYWN0dWFsRGF0YSA9IGFjdHVhbERhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIGFjdHVhbERhdGEsIG1ldGEpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aENsZWFuRGF0YSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVQSV9DT09LSUVfS0VZOiAnZXBpY2VudGVyLnByb2plY3QudG9rZW4nLFxuICAgIEVQSV9TRVNTSU9OX0tFWTogJ2VwaWNlbnRlci51c2VyLnNlc3Npb24nLFxuICAgIFNUUkFURUdZX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLXNjZW5hcmlvJ1xufTsiLCIvKipcbiogIyMgUnVuIE1hbmFnZXJcbipcbiogVGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBhY2Nlc3MgdG8gcnVucyBmb3IgeW91ciBwcm9qZWN0LiBUaGlzIGFsbG93cyB5b3UgdG8gcmVhZCBhbmQgdXBkYXRlIHZhcmlhYmxlcywgY2FsbCBvcGVyYXRpb25zLCBldGMuIEFkZGl0aW9uYWxseSwgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLiBTcGVjaWZpY2FsbHksIHlvdSBjYW4gc2VsZWN0IFtydW4gY3JlYXRpb24gc3RyYXRlZ2llcyAocnVsZXMpXSguLi8uLi9zdHJhdGVneS8pIGZvciB3aGljaCBydW5zIGVuZCB1c2VycyBvZiB5b3VyIHByb2plY3Qgd29yayB3aXRoIHdoZW4gdGhleSBsb2cgaW4gdG8geW91ciBwcm9qZWN0LlxuKlxuKiBUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGNyZWF0ZSBuZXcgcnVucywgaW5jbHVkaW5nIHRoZSBFcGljZW50ZXIuanMgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSwgdGhlIFJFU0ZUZnVsIFtSdW4gQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkpIGFuZCB0aGUgW01vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLykuIEhvd2V2ZXIsIGZvciBzb21lIHByb2plY3RzIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gcGljayB1cCB3aGVyZSB0aGUgdXNlciBsZWZ0IG9mZiwgdXNpbmcgYW4gZXhpc3RpbmcgcnVuLiBBbmQgaW4gc29tZSBwcm9qZWN0cywgd2hldGhlciB0byBjcmVhdGUgYSBuZXcgcnVuIG9yIHVzZSBhbiBleGlzdGluZyBvbmUgaXMgY29uZGl0aW9uYWwsIGZvciBleGFtcGxlIGJhc2VkIG9uIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZXhpc3RpbmcgcnVuIG9yIHlvdXIgb3duIGtub3dsZWRnZSBhYm91dCB0aGUgbW9kZWwuIFRoZSBSdW4gTWFuYWdlciBwcm92aWRlcyB0aGlzIGxldmVsIG9mIGNvbnRyb2w6IHlvdXIgY2FsbCB0byBgZ2V0UnVuKClgLCByYXRoZXIgdGhhbiBhbHdheXMgcmV0dXJuaW5nIGEgbmV3IHJ1biwgcmV0dXJucyBhIHJ1biBiYXNlZCBvbiB0aGUgc3RyYXRlZ3kgeW91J3ZlIHNwZWNpZmllZC4gKE5vdGUgdGhhdCBtYW55IG9mIHRoZSBFcGljZW50ZXIgc2FtcGxlIHByb2plY3RzIHVzZSBhIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LCBiZWNhdXNlIGdlbmVyYWxseSB0aGUgc2FtcGxlIHByb2plY3RzIGFyZSBwbGF5ZWQgaW4gb25lIGVuZCB1c2VyIHNlc3Npb24gYW5kIGRvbid0IGNhcmUgYWJvdXQgcnVuIHN0YXRlcyBvciBydW4gc3RyYXRlZ2llcy4pXG4qXG4qXG4qICMjIyBVc2luZyB0aGUgUnVuIE1hbmFnZXIgdG8gY3JlYXRlIGFuZCBhY2Nlc3MgcnVuc1xuKlxuKiBUbyB1c2UgdGhlIFJ1biBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuKlxuKiAgICogYHJ1bmA6IChyZXF1aXJlZCkgUnVuIG9iamVjdC4gTXVzdCBjb250YWluOlxuKiAgICAgICAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICAgICAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4qICAgICAgICogYG1vZGVsYDogVGhlIG5hbWUgb2YgeW91ciBwcmltYXJ5IG1vZGVsIGZpbGUuIChTZWUgbW9yZSBvbiBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4pXG4qICAgICAgICogYHNjb3BlYDogKG9wdGlvbmFsKSBTY29wZSBvYmplY3QgZm9yIHRoZSBydW4sIGZvciBleGFtcGxlIGBzY29wZS5ncm91cGAgd2l0aCB2YWx1ZSBvZiB0aGUgbmFtZSBvZiB0aGUgZ3JvdXAuXG4qICAgICAgICogYHNlcnZlcmA6IChvcHRpb25hbCkgQW4gb2JqZWN0IHdpdGggb25lIGZpZWxkLCBgaG9zdGAuIFRoZSB2YWx1ZSBvZiBgaG9zdGAgaXMgdGhlIHN0cmluZyBgYXBpLmZvcmlvLmNvbWAsIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4qICAgICAgICogYGZpbGVzYDogKG9wdGlvbmFsKSBJZiBhbmQgb25seSBpZiB5b3UgYXJlIHVzaW5nIGEgVmVuc2ltIG1vZGVsIGFuZCB5b3UgaGF2ZSBhZGRpdGlvbmFsIGRhdGEgdG8gcGFzcyBpbiB0byB5b3VyIG1vZGVsLCB5b3UgY2FuIHBhc3MgYSBgZmlsZXNgIG9iamVjdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgZmlsZXMsIGZvciBleGFtcGxlOiBgXCJmaWxlc1wiOiB7XCJkYXRhXCI6IFwibXlFeHRyYURhdGEueGxzXCJ9YC4gKE5vdGUgdGhhdCB5b3UnbGwgYWxzbyBuZWVkIHRvIGFkZCB0aGlzIHNhbWUgZmlsZXMgb2JqZWN0IHRvIHlvdXIgVmVuc2ltIFtjb25maWd1cmF0aW9uIGZpbGVdKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltLykuKSBTZWUgdGhlIFt1bmRlcmx5aW5nIE1vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLyNwb3N0LWNyZWF0aW5nLWEtbmV3LXJ1bi1mb3ItdGhpcy1wcm9qZWN0KSBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbi5cbipcbiogICAqIGBzdHJhdGVneWA6IChvcHRpb25hbCkgUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4qXG4qICAgKiBgc2Vzc2lvbktleWA6IChvcHRpb25hbCkgTmFtZSBvZiBicm93c2VyIGNvb2tpZSBpbiB3aGljaCB0byBzdG9yZSBydW4gaW5mb3JtYXRpb24sIGluY2x1ZGluZyBydW4gaWQuIE1hbnkgY29uZGl0aW9uYWwgc3RyYXRlZ2llcywgaW5jbHVkaW5nIHRoZSBwcm92aWRlZCBzdHJhdGVnaWVzLCByZWx5IG9uIHRoaXMgYnJvd3NlciBjb29raWUgdG8gc3RvcmUgdGhlIHJ1biBpZCBhbmQgaGVscCBtYWtlIHRoZSBkZWNpc2lvbiBvZiB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZS4gVGhlIG5hbWUgb2YgdGhpcyBjb29raWUgZGVmYXVsdHMgdG8gYGVwaWNlbnRlci1zY2VuYXJpb2AgYW5kIGNhbiBiZSBzZXQgd2l0aCB0aGUgYHNlc3Npb25LZXlgIHBhcmFtZXRlci5cbipcbipcbiogQWZ0ZXIgaW5zdGFudGlhdGluZyBhIFJ1biBNYW5hZ2VyLCBtYWtlIGEgY2FsbCB0byBgZ2V0UnVuKClgIHdoZW5ldmVyIHlvdSBuZWVkIHRvIGFjY2VzcyBhIHJ1biBmb3IgdGhpcyBlbmQgdXNlci4gVGhlIGBSdW5NYW5hZ2VyLnJ1bmAgY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLiBUaGUgUnVuIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBhY2Nlc3MgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy5cbipcbiogKipFeGFtcGxlKipcbipcbiogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiogICAgICAgICAgIHJ1bjoge1xuKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJyxcbiogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiogICAgICAgICAgIH0sXG4qICAgICAgICAgICBzdHJhdGVneTogJ2Fsd2F5cy1uZXcnLFxuKiAgICAgICAgICAgc2Vzc2lvbktleTogJ2VwaWNlbnRlci1zZXNzaW9uJ1xuKiAgICAgICB9KTtcbiogICAgICAgcm0uZ2V0UnVuKClcbiogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuKiAgICAgICAgICAgICAgIC8vIHRoZSByZXR1cm4gdmFsdWUgb2YgZ2V0UnVuKCkgaXMgYSBydW4gb2JqZWN0XG4qICAgICAgICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gYWxzbyBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuKiAgICAgICAgICAgICAgIC8vIHNvIGFueSBSdW4gU2VydmljZSBtZXRob2QgaXMgdmFsaWQgaGVyZVxuKiAgICAgICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiogICAgICAgfSlcbipcbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBzdHJhdGVnaWVzTWFwID0gcmVxdWlyZSgnLi9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcCcpO1xudmFyIHNwZWNpYWxPcGVyYXRpb25zID0gcmVxdWlyZSgnLi9zcGVjaWFsLW9wZXJhdGlvbnMnKTtcbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcblxuXG5mdW5jdGlvbiBwYXRjaFJ1blNlcnZpY2Uoc2VydmljZSwgbWFuYWdlcikge1xuICAgIGlmIChzZXJ2aWNlLnBhdGNoZWQpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuXG4gICAgdmFyIG9yaWcgPSBzZXJ2aWNlLmRvO1xuICAgIHNlcnZpY2UuZG8gPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHJlc2VydmVkT3BzID0gT2JqZWN0LmtleXMoc3BlY2lhbE9wZXJhdGlvbnMpO1xuICAgICAgICBpZiAocmVzZXJ2ZWRPcHMuaW5kZXhPZihvcGVyYXRpb24pID09PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG9yaWcuYXBwbHkoc2VydmljZSwgYXJndW1lbnRzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT3BlcmF0aW9uc1tvcGVyYXRpb25dLmNhbGwoc2VydmljZSwgcGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBzZXJ2aWNlLnBhdGNoZWQgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHNlcnZpY2U7XG59XG5cblxuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cblxuICAgIHN0cmF0ZWd5OiAnbmV3LWlmLWluaXRpYWxpemVkJ1xufTtcblxuZnVuY3Rpb24gUnVuTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMucnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICB0aGlzLnJ1biA9IHRoaXMub3B0aW9ucy5ydW47XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5ydW4gPSBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMucnVuKTtcbiAgICB9XG5cbiAgICBwYXRjaFJ1blNlcnZpY2UodGhpcy5ydW4sIHRoaXMpO1xuXG4gICAgdmFyIFN0cmF0ZWd5Q3RvciA9IHR5cGVvZiB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgPT09ICdmdW5jdGlvbicgPyB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgOiBzdHJhdGVnaWVzTWFwW3RoaXMub3B0aW9ucy5zdHJhdGVneV07XG5cbiAgICBpZiAoIVN0cmF0ZWd5Q3Rvcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NwZWNpZmllZCBydW4gY3JlYXRpb24gc3RyYXRlZ3kgd2FzIGludmFsaWQ6JywgdGhpcy5vcHRpb25zLnN0cmF0ZWd5KTtcbiAgICB9XG5cbiAgICB0aGlzLnN0cmF0ZWd5ID0gbmV3IFN0cmF0ZWd5Q3Rvcih0aGlzLnJ1biwgdGhpcy5vcHRpb25zKTtcbn1cblxuUnVuTWFuYWdlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSAnZ29vZCcgcnVuLlxuICAgICAqXG4gICAgICogQSBnb29kIHJ1biBpcyBkZWZpbmVkIGJ5IHRoZSBzdHJhdGVneS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBzdHJhdGVneSBpcyBgYWx3YXlzLW5ld2AsIHRoZSBjYWxsXG4gICAgICogdG8gYGdldFJ1bigpYCBhbHdheXMgcmV0dXJucyBhIG5ld2x5IGNyZWF0ZWQgcnVuOyBpZiB0aGUgc3RyYXRlZ3kgaXMgYG5ldy1pZi1wZXJzaXN0ZWRgLFxuICAgICAqIGBnZXRSdW4oKWAgY3JlYXRlcyBhIG5ldyBydW4gaWYgdGhlIHByZXZpb3VzIHJ1biBpcyBpbiBhIHBlcnNpc3RlZCBzdGF0ZSwgb3RoZXJ3aXNlXG4gICAgICogaXQgcmV0dXJucyB0aGUgcHJldmlvdXMgcnVuLiBTZWUgW1J1biBNYW5hZ2VyIFN0cmF0ZWdpZXNdKC4uLy4uL3N0cmF0ZWd5LykgZm9yIG1vcmUgb24gc3RyYXRlZ2llcy5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5nZXRSdW4oKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqIEByZXR1cm4geyRwcm9taXNlfSBQcm9taXNlIHRvIGNvbXBsZXRlIHRoZSBjYWxsLlxuICAgICAqL1xuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdHJhdGVneVxuICAgICAgICAgICAgICAgIC5nZXRSdW4oKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSBuZXcgcnVuLCByZWdhcmRsZXNzIG9mIHN0cmF0ZWd5OiBmb3JjZSBjcmVhdGlvbiBvZiBhIG5ldyBydW4uXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgcm0ucmVzZXQoKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIChuZXcpIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBydW5TZXJ2aWNlT3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgUnVuIFNlcnZpY2UuIFNlZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBmb3IgbW9yZS5cbiAgICAgKi9cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5LnJlc2V0KHJ1blNlcnZpY2VPcHRpb25zKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJ1bk1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIC8vIGFsd2F5cyBjcmVhdGUgYSBuZXcgcnVuIVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1ha2VTZXEgPSByZXF1aXJlKCcuLi8uLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFNlc3Npb25TdG9yZSA9IHJlcXVpcmUoJy4uLy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBVcmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgc2Vzc2lvblN0b3JlID0gbmV3IFNlc3Npb25TdG9yZSh7fSk7XG52YXIgdXJsU2VydmljZSA9IG5ldyBVcmxTZXJ2aWNlKCk7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9rZXktbmFtZXMnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHNlc3Npb25LZXk6IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZLFxuICAgIHBhdGg6ICcnXG59O1xuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBwYXRoKSB7XG4gICAgaWYgKCFwYXRoKSB7XG4gICAgICAgIGlmICghdXJsU2VydmljZS5pc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgICAgICBwYXRoID0gJy8nICsgW3VybFNlcnZpY2UuYXBwUGF0aCwgdXJsU2VydmljZS5hY2NvdW50UGF0aCwgdXJsU2VydmljZS5wcm9qZWN0UGF0aF0uam9pbignLycpO1xuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHdlIGRvbid0IGdldCBjb25zZWN1dGVpdmUgJy8nIHNvIHdlIGhhdmUgYSB2YWxpZCBwYXRoIGZvciB0aGUgc2Vzc2lvblxuICAgICAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZSgvXFwvezIsfS9nLCcvJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYXRoID0gJyc7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gc2V0IHRoZSBzZWVzaW9uS2V5IGZvciB0aGUgcnVuXG4gICAgc2Vzc2lvblN0b3JlLnNldChzZXNzaW9uS2V5LCBKU09OLnN0cmluZ2lmeSh7IHJ1bklkOiBydW4uaWQgfSksIHsgcm9vdDogcGF0aCB9KTtcbn1cblxuLyoqXG4qIENvbmRpdGlvbmFsIENyZWF0aW9uIFN0cmF0ZWd5XG4qIFRoaXMgc3RyYXRlZ3kgd2lsbCB0cnkgdG8gZ2V0IHRoZSBydW4gc3RvcmVkIGluIHRoZSBjb29raWUgYW5kXG4qIGV2YWx1YXRlIGlmIG5lZWRzIHRvIGNyZWF0ZSBhIG5ldyBydW4gYnkgY2FsbGluZyB0aGUgJ2NvbmRpdGlvbicgZnVuY3Rpb25cbiovXG5cbi8qIGpzaGludCBlcW51bGw6IHRydWUgKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KHJ1blNlcnZpY2UsIGNvbmRpdGlvbiwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChjb25kaXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb25kaXRpb25hbCBzdHJhdGVneSBuZWVkcyBhIGNvbmRpdGlvbiB0byBjcmVhdGV0ZSBhIHJ1bicpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fYXV0aCA9IG5ldyBBdXRoTWFuYWdlcigpO1xuICAgICAgICB0aGlzLnJ1biA9IG1ha2VTZXEocnVuU2VydmljZSk7XG4gICAgICAgIHRoaXMuY29uZGl0aW9uID0gdHlwZW9mIGNvbmRpdGlvbiAhPT0gJ2Z1bmN0aW9uJyA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNvbmRpdGlvbjsgfSA6IGNvbmRpdGlvbjtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9LFxuXG4gICAgcnVuT3B0aW9uc1dpdGhTY29wZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdXNlclNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiB1c2VyU2Vzc2lvbi5ncm91cE5hbWUgfVxuICAgICAgICB9LCB0aGlzLnJ1bk9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBvcHQgPSB0aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5ydW5cbiAgICAgICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgc2V0UnVuSW5TZXNzaW9uKF90aGlzLm9wdGlvbnMuc2Vzc2lvbktleSwgcnVuLCBfdGhpcy5vcHRpb25zLnBhdGgpO1xuICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmUuZ2V0KHRoaXMub3B0aW9ucy5zZXNzaW9uS2V5KSk7XG5cbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRBbmRDaGVjayhydW5TZXNzaW9uKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgX2xvYWRBbmRDaGVjazogZnVuY3Rpb24gKHJ1blNlc3Npb24pIHtcbiAgICAgICAgdmFyIHNob3VsZENyZWF0ZSA9IGZhbHNlO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1blxuICAgICAgICAgICAgLmxvYWQocnVuU2Vzc2lvbi5ydW5JZCwgbnVsbCwge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uIChydW4sIG1zZywgaGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBzaG91bGRDcmVhdGUgPSBfdGhpcy5jb25kaXRpb24uY2FsbChfdGhpcywgcnVuLCBoZWFkZXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIGlmIChzaG91bGRDcmVhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9wdCA9IF90aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgbmVlZCB0byBkbyB0aGlzLCBvbiB0aGUgb3JpZ2luYWwgcnVuU2VydmljZSAoaWUgbm90IHNlcXVlbmNpYWxpemVkKVxuICAgICAgICAgICAgICAgICAgICAvLyBzbyB3ZSBkb24ndCBnZXQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1bi5vcmlnaW5hbC5jcmVhdGUob3B0KVxuICAgICAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oX3RoaXMub3B0aW9ucy5zZXNzaW9uS2V5LCBydW4pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnN0YXJ0KCk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSAgPSBydW5TZXJ2aWNlO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSBuZXdseSBjcmVhdGVkIHJ1blxuICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoKS5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSh0aGlzLnJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vaWRlbnRpdHktc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0b3JlOiB7XG4gICAgICAgIHN5bmNocm9ub3VzOiB0cnVlXG4gICAgfVxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcblxuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMud29ybGRBcGkgPSBuZXcgV29ybGRBcGlBZGFwdGVyKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciB3b3JsZEFwaSA9IHRoaXMud29ybGRBcGk7XG4gICAgICAgIHZhciBtb2RlbCA9IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAoIWN1clVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDAsIGVycm9yOiAnV2UgbmVlZCBhbiBhdXRoZW50aWNhdGVkIHVzZXIgdG8gam9pbiBhIG11bHRpcGxheWVyIHdvcmxkLiAoRVJSOiBubyB1c2VySWQgaW4gc2Vzc2lvbiknIH0sIHNlc3Npb24pLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsb2FkUnVuRnJvbVdvcmxkID0gZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDQsIGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IGluIGFueSB3b3JsZC4nIH0sIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oX3RoaXMuX2xvYWRSdW4pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgZHRkLnJlamVjdChlcnJvciwgc2Vzc2lvbiwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIF9sb2FkUnVuOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIFN0YXRlQXBpID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICAgICAgdGhpcy5fc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICAgICAgdGhpcy5zdGF0ZUFwaSA9IG5ldyBTdGF0ZUFwaSgpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZEFuZENoZWNrID0gdGhpcy5fbG9hZEFuZENoZWNrLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVSdW4gPSB0aGlzLl9yZXN0b3JlUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2dldEFsbFJ1bnMgPSB0aGlzLl9nZXRBbGxSdW5zLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0QWxsUnVucygpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9sb2FkQW5kQ2hlY2spO1xuICAgIH0sXG5cbiAgICBfZ2V0QWxsUnVuczogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2UodGhpcy5fc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9Jyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5xdWVyeSh7XG4gICAgICAgICAgICAndXNlci5pZCc6IHNlc3Npb24udXNlcklkIHx8ICcwMDAwJyxcbiAgICAgICAgICAgICdzY29wZS5ncm91cCc6IHNlc3Npb24uZ3JvdXBOYW1lXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVucykge1xuICAgICAgICBpZiAoIXJ1bnMgfHwgIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGVDb21wID0gZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIuZGF0ZSkgLSBuZXcgRGF0ZShhLmRhdGUpOyB9O1xuICAgICAgICB2YXIgbGF0ZXN0UnVuID0gcnVucy5zb3J0KGRhdGVDb21wKVswXTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHNob3VsZFJlcGxheSA9IGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGxhdGVzdFJ1bi5pZCwgbnVsbCwge1xuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVwbGF5ID0gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2hvdWxkUmVwbGF5ID8gX3RoaXMuX3Jlc3RvcmVSdW4ocnVuLmlkKSA6IHJ1bjtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9yZXN0b3JlUnVuOiBmdW5jdGlvbiAocnVuSWQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVBcGkucmVwbGF5KHsgcnVuSWQ6IHJ1bklkIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJ1bihyZXNwLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW4ubG9hZChpZCwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgICduZXctaWYtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLFxuICAgICduZXctaWYtcGVyc2lzdGVkJzogcmVxdWlyZSgnLi9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1taXNzaW5nJzogcmVxdWlyZSgnLi9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpLFxuICAgICdhbHdheXMtbmV3JzogcmVxdWlyZSgnLi9hbHdheXMtbmV3LXN0cmF0ZWd5JyksXG4gICAgJ211bHRpcGxheWVyJzogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdwZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXInOiByZXF1aXJlKCcuL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneScpLFxuICAgICdub25lJzogcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgdmFsaWRGaWx0ZXI6IHsgc2F2ZWQ6IHRydWUgfVxufTtcblxuZnVuY3Rpb24gU2NlbmFyaW9NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMucnVuU2VydmljZSA9IHRoaXMub3B0aW9ucy5ydW4gfHwgbmV3IFJ1blNlcnZpY2UodGhpcy5vcHRpb25zKTtcbn1cblxuU2NlbmFyaW9NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy52YWxpZEZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlcik7XG4gICAgfSxcblxuICAgIGxvYWRWYXJpYWJsZXM6IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UucXVlcnkodGhpcy5maWx0ZXIsIHsgaW5jbHVkZTogdmFycyB9KTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgbWV0YSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2VydmljZShydW4pLnNhdmUoJC5leHRlbmQodHJ1ZSwge30sIHsgc2F2ZWQ6IHRydWUgfSwgbWV0YSkpO1xuICAgIH0sXG5cbiAgICBhcmNoaXZlOiBmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSh7IHNhdmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuXG4gICAgX2dldFNlcnZpY2U6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW4gfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdvYmplY3QnICYmIHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NhdmUgbWV0aG9kIHJlcXVpcmVzIGEgcnVuIHNlcnZpY2Ugb3IgYSBydW5JZCcpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW5JZCB9KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICByZXNldDogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucywgbWFuYWdlcikge1xuICAgICAgICByZXR1cm4gbWFuYWdlci5yZXNldChvcHRpb25zKTtcbiAgICB9XG59O1xuIiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9ICByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG4vLyB2YXIgZGVmYXVsdHMgPSB7XG4vLyAgYWNjb3VudDogJycsXG4vLyAgcHJvamVjdDogJycsXG4vLyAgZ3JvdXA6ICcnLFxuLy8gIHRyYW5zcG9ydDoge1xuLy8gIH1cbi8vIH07XG5cblxuZnVuY3Rpb24gYnVpbGRTdHJhdGVneSh3b3JsZElkLCBkdGQpIHtcblxuICAgIHJldHVybiBmdW5jdGlvbiBDdG9yKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICAkLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm90IGltcGxlbWVudGQuIE5lZWQgYXBpIGNoYW5nZXMnKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlLmNhbGwodGhpcywgcnVuLCBfdGhpcy5ydW5TZXJ2aWNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcklkYCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSBncm91cCBmb3IgdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bih7bW9kZWw6ICdteU1vZGVsLnB5J30pXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBtb2RlbGAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgbW9kZWwgZmlsZS4gUmVxdWlyZWQgaWYgbm90IGFscmVhZHkgcGFzc2VkIGluIGFzIGBydW4ubW9kZWxgIHdoZW4gdGhlIFdvcmxkIE1hbmFnZXIgaXMgY3JlYXRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgX3RoaXMub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJtLmdldFJ1bigpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHJ1biwgcm0ucnVuU2VydmljZSwgcm0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5nZXRDdXJyZW50V29ybGQoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bik7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIGFwaSk7XG59O1xuIiwiLyoqXG4gKiAjI0ZpbGUgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGlzIGlzIHVzZWQgdG8gdXBsb2FkL2Rvd25sb2FkIGZpbGVzIGRpcmVjdGx5IG9udG8gRXBpY2VudGVyLCBhbmFsb2dvdXMgdG8gdXNpbmcgdGhlIEZpbGUgTWFuYWdlciBVSSBpbiBFcGljZW50ZXIgZGlyZWN0bHkgb3IgU0ZUUGluZyBmaWxlcyBpbi4gVGhlIEFzc2V0IEFQSSBpcyB0eXBpY2FsbHkgdXNlZCBmb3IgYWxsIHByb2plY3QgdXNlLWNhc2VzLCBhbmQgaXQncyB1bmxpa2VseSB0aGlzIEZpbGUgU2VydmljZSB3aWxsIGJlIHVzZWQgZGlyZWN0bHkgZXhjZXB0IGJ5IEFkbWluIHRvb2xzIChlLmcuIEZsb3cgSW5zcGVjdG9yKS5cbiAqXG4gKiBQYXJ0aWFsbHkgaW1wbGVtZW50ZWQuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCBzdG9yZS5nZXQoJ2VwaWNlbnRlci50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZmlsZScpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQXN5bmNBUEkgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgYSBkaXJlY3RvcnkgbGlzdGluZywgb3IgY29udGVudHMgb2YgYSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGZpbGVQYXRoYCAgIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZm9sZGVyVHlwZWAgT25lIG9mIE1vZGVsfFN0YXRpY3xOb2RlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBnZXRDb250ZW50czogZnVuY3Rpb24gKGZpbGVQYXRoLCBmb2xkZXJUeXBlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IGZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbi8vIHZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGtleU5hbWVzID0gcmVxdWlyZSgnLi4vbWFuYWdlcnMva2V5LW5hbWVzJyk7XG5cbnZhciBhcGlFbmRwb2ludCA9ICdhc3NldCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZShzdG9yZS5nZXQoa2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZKSB8fCAne30nKTtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9DT09LSUVfS0VZKSB8fCAnJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gRGVmYXVsdHMgdG8gc2Vzc2lvbidzIGBncm91cE5hbWVgLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogc2Vzc2lvbi51c2VySWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgc2NvcGUgZm9yIHRoZSBhc3NldC4gVmFsaWQgdmFsdWVzIGFyZTogYHVzZXJgLCBgZ3JvdXBgLCBhbmQgYHByb2plY3RgLiBTZWUgYWJvdmUgZm9yIHRoZSByZXF1aXJlZCBwZXJtaXNzaW9ucyB0byB3cml0ZSB0byBlYWNoIHNjb3BlLiBEZWZhdWx0cyB0byBgdXNlcmAsIG1lYW5pbmcgdGhlIGN1cnJlbnQgZW5kIHVzZXIgb3IgYSBmYWNpbGl0YXRvciBpbiB0aGUgZW5kIHVzZXIncyBncm91cCBjYW4gZWRpdCB0aGUgYXNzZXQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBzY29wZTogJ3VzZXInLFxuICAgICAgICAvKipcbiAgICAgICAgICogRGV0ZXJtaW5lcyBpZiBhIHJlcXVlc3QgdG8gbGlzdCB0aGUgYXNzZXRzIGluIGEgc2NvcGUgaW5jbHVkZXMgdGhlIGNvbXBsZXRlIFVSTCBmb3IgZWFjaCBhc3NldCAoYHRydWVgKSwgb3Igb25seSB0aGUgZmlsZSBuYW1lcyBvZiB0aGUgYXNzZXRzIChgZmFsc2VgKS4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGZ1bGxVcmw6IHRydWUsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgdHJhbnNwb3J0IG9iamVjdCBjb250YWlucyB0aGUgb3B0aW9ucyBwYXNzZWQgdG8gdGhlIFhIUiByZXF1ZXN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7XG4gICAgICAgICAgICBwcm9jZXNzRGF0YTogZmFsc2VcbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIGFzc2V0QXBpUGFyYW1zID0gWydlbmNvZGluZycsICdkYXRhJywgJ2NvbnRlbnRUeXBlJ107XG4gICAgdmFyIHNjb3BlQ29uZmlnID0ge1xuICAgICAgICB1c2VyOiBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSxcbiAgICAgICAgZ3JvdXA6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10sXG4gICAgICAgIHByb2plY3Q6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0J10sXG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZUZpbGVuYW1lID0gZnVuY3Rpb24gKGZpbGVuYW1lKSB7XG4gICAgICAgIGlmICghZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZmlsZW5hbWUgaXMgbmVlZGVkLicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZVVybFBhcmFtcyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICBpZiAoIXBhcnRLZXlzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Njb3BlIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cblxuICAgICAgICAkLmVhY2gocGFydEtleXMsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICghb3B0aW9uc1t0aGlzXSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzICsgJyBwYXJhbWV0ZXIgaXMgbmVlZGVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgdmFyIGJ1aWxkVXJsID0gZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgIHZhbGlkYXRlVXJsUGFyYW1zKG9wdGlvbnMpO1xuICAgICAgICB2YXIgcGFydEtleXMgPSBzY29wZUNvbmZpZ1tvcHRpb25zLnNjb3BlXTtcbiAgICAgICAgdmFyIHBhcnRzID0gJC5tYXAocGFydEtleXMsIGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zW2tleV07XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgcHJldmVudHMgYWRkaW5nIGEgdHJhaWxpbmcgLyBpbiB0aGUgVVJMIGFzIHRoZSBBc3NldCBBUElcbiAgICAgICAgICAgIC8vIGRvZXMgbm90IHdvcmsgY29ycmVjdGx5IHdpdGggaXRcbiAgICAgICAgICAgIGZpbGVuYW1lID0gJy8nICsgZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHBhcnRzLmpvaW4oJy8nKSArIGZpbGVuYW1lO1xuICAgIH07XG5cbiAgICAvLyBQcml2YXRlIGZ1bmN0aW9uLCBhbGwgcmVxdWVzdHMgZm9sbG93IGEgbW9yZSBvciBsZXNzIHNhbWUgYXBwcm9hY2ggdG9cbiAgICAvLyB1c2UgdGhlIEFzc2V0IEFQSSBhbmQgdGhlIGRpZmZlcmVuY2UgaXMgdGhlIEhUVFAgdmVyYlxuICAgIC8vXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBtZXRob2RgIChSZXF1aXJlZCkgSFRUUCB2ZXJiXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS9yZXBsYWNlL2NyZWF0ZVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUElcbiAgICAvLyBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgdmFyIHVwbG9hZCA9IGZ1bmN0aW9uIChtZXRob2QsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVGaWxlbmFtZShmaWxlbmFtZSk7XG4gICAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgcGFyYW1ldGVyIGlzIGNsZWFuXG4gICAgICAgIG1ldGhvZCA9IG1ldGhvZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB2YXIgY29udGVudFR5cGUgPSBwYXJhbXMgaW5zdGFuY2VvZiBGb3JtRGF0YSA9PT0gdHJ1ZSA/IGZhbHNlIDogJ2FwcGxpY2F0aW9uL2pzb24nO1xuICAgICAgICBpZiAoY29udGVudFR5cGUgPT09ICdhcHBsaWNhdGlvbi9qc29uJykge1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIGFzc2V0QXBpUGFyYW1zKTtcbiAgICAgICAgfSBlbHNlIHsgLy8gZWxzZSB3ZSdyZSBzZW5kaW5nIGZvcm0gZGF0YSB3aGljaCBnb2VzIGRpcmVjdGx5IGluIHJlcXVlc3QgYm9keVxuICAgICAgICAgICAgLy8gRm9yIG11bHRpcGFydC9mb3JtLWRhdGEgdXBsb2FkcyB0aGUgZmlsZW5hbWUgaXMgbm90IHNldCBpbiB0aGUgVVJMLFxuICAgICAgICAgICAgLy8gaXQncyBnZXR0aW5nIHBpY2tlZCBieSB0aGUgRm9ybURhdGEgZmllbGQgZmlsZW5hbWUuXG4gICAgICAgICAgICBmaWxlbmFtZSA9IG1ldGhvZCA9PT0gJ3Bvc3QnIHx8IG1ldGhvZCA9PT0gJ3B1dCcgPyAnJyA6IGZpbGVuYW1lO1xuICAgICAgICB9XG4gICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCwgY29udGVudFR5cGU6IGNvbnRlbnRUeXBlIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwW21ldGhvZF0ocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS4gVGhlIHNlcnZlciByZXR1cm5zIGFuIGVycm9yIChzdGF0dXMgY29kZSBgNDA5YCwgY29uZmxpY3QpIGlmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLCBzb1xuICAgICAgICAqIGNoZWNrIGZpcnN0IHdpdGggYSBgbGlzdCgpYCBvciBhIGBnZXQoKWAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBhYSA9IG5ldyBGLnNlcnZpY2UuQXNzZXQoe1xuICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAgICAqICAgICAgICAgIHVzZXJJZDogJydcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAgICAgICAgKiAgICAgICBhYS5jcmVhdGUoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gICAgICAgICogICAgICAgICAgIGNvbnRlbnRUeXBlOiAndGV4dC9wbGFpbidcbiAgICAgICAgKiAgICAgICB9LCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyBhbHRlcm5hdGl2ZWx5LCBjcmVhdGUgYSBuZXcgYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJ1cGxvYWQtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5VcGxvYWQgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3VwbG9hZC1maWxlJykub24oJ3N1Ym1pdCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLmNyZWF0ZShmaWxlbmFtZSwgZGF0YSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gY3JlYXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUEkuIFJlcXVpcmVkIGlmIHRoZSBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYCwgb3RoZXJ3aXNlIGlnbm9yZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZW5jb2RpbmdgIEVpdGhlciBgSEVYYCBvciBgQkFTRV82NGAuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmRhdGFgIFRoZSBlbmNvZGVkIGRhdGEgZm9yIHRoZSBmaWxlLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5jb250ZW50VHlwZWAgVGhlIG1pbWUgdHlwZSBvZiB0aGUgZmlsZS4gT3B0aW9uYWwuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3Bvc3QnLCBmaWxlbmFtZSwgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGEgZmlsZSBmcm9tIHRoZSBBc3NldCBBUEksIGZldGNoaW5nIHRoZSBhc3NldCBjb250ZW50LiAoVG8gZ2V0IGEgbGlzdFxuICAgICAgICAqIG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZSwgdXNlIGBsaXN0KClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byByZXRyaWV2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBnZXRTZXJ2aWNlT3B0aW9ucyA9IF9waWNrKHNlcnZpY2VPcHRpb25zLCBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSk7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBnZXRTZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBsaXN0IG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5saXN0KHsgZnVsbFVybDogdHJ1ZSB9KS50aGVuKGZ1bmN0aW9uKGZpbGVMaXN0KXtcbiAgICAgICAgKiAgICAgICAgICAgY29uc29sZS5sb2coJ2FycmF5IG9mIGZpbGVzID0gJywgZmlsZUxpc3QpO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5zY29wZWAgKE9wdGlvbmFsKSBUaGUgc2NvcGUgKGB1c2VyYCwgYGdyb3VwYCwgYHByb2plY3RgKS5cbiAgICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGBvcHRpb25zLmZ1bGxVcmxgIChPcHRpb25hbCkgRGV0ZXJtaW5lcyBpZiB0aGUgbGlzdCBvZiBhc3NldHMgaW4gYSBzY29wZSBpbmNsdWRlcyB0aGUgY29tcGxldGUgVVJMIGZvciBlYWNoIGFzc2V0IChgdHJ1ZWApLCBvciBvbmx5IHRoZSBmaWxlIG5hbWVzIG9mIHRoZSBhc3NldHMgKGBmYWxzZWApLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybCgnJywgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuICAgICAgICAgICAgdmFyIGZ1bGxVcmwgPSBnZXRPcHRpb25zLmZ1bGxVcmw7XG5cbiAgICAgICAgICAgIGlmICghZnVsbFVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZnVsbFBhdGhGaWxlcyA9ICQubWFwKGZpbGVzLCBmdW5jdGlvbiAoZmlsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoZnVsbFBhdGhGaWxlcywgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlcGxhY2VzIGFuIGV4aXN0aW5nIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyByZXBsYWNlIGFuIGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLnJlcGxhY2UoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhObFkyOXVaQ0IwWlhOMElHWnBiR1V1JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJyZXBsYWNlLWZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwicmVwbGFjZS1maWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5SZXBsYWNlIG15RmlsZTwvYnV0dG9uPlxuICAgICAgICAqICAgICAgIC8vIDwvZm9ybT5cbiAgICAgICAgKiAgICAgICAvL1xuICAgICAgICAqICAgICAgICQoJyNyZXBsYWNlLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI3JlcGxhY2UtZmlsZW5hbWUnKS52YWwoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICAgICAgICAqICAgICAgICAgIGRhdGEuYXBwZW5kKCdmaWxlJywgaW5wdXRDb250cm9sLmZpbGVzWzBdLCBmaWxlbmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICBhYS5yZXBsYWNlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgYmVpbmcgcmVwbGFjZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgcmVwbGFjZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3B1dCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5kZWxldGUoc2FtcGxlRmlsZU5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ2RlbGV0ZScsIGZpbGVuYW1lLCB7fSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYXNzZXRVcmw6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlIHByb3ZpZGVzIG1ldGhvZHMgZm9yIGxvZ2dpbmcgaW4gYW5kIGxvZ2dpbmcgb3V0LiBPbiBsb2dpbiwgdGhpcyBzZXJ2aWNlIGNyZWF0ZXMgYW5kIHJldHVybnMgYSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAqXG4gKiBVc2VyIGFjY2VzcyB0b2tlbnMgYXJlIHJlcXVpcmVkIGZvciBlYWNoIGNhbGwgdG8gRXBpY2VudGVyLiAoU2VlIFtQcm9qZWN0IEFjY2Vzc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4pXG4gKlxuICogSWYgeW91IG5lZWQgYWRkaXRpb25hbCBmdW5jdGlvbmFsaXR5IC0tIHN1Y2ggYXMgdHJhY2tpbmcgc2Vzc2lvbiBpbmZvcm1hdGlvbiwgZWFzaWx5IHJldHJpZXZpbmcgdGhlIHVzZXIgdG9rZW4sIG9yIGdldHRpbmcgdGhlIGdyb3VwcyB0byB3aGljaCBhbiBlbmQgdXNlciBiZWxvbmdzIC0tIGNvbnNpZGVyIHVzaW5nIHRoZSBbQXV0aG9yaXphdGlvbiBNYW5hZ2VyXSguLi9hdXRoLW1hbmFnZXIvKSBpbnN0ZWFkLlxuICpcbiAqICAgICAgdmFyIGF1dGggPSBuZXcgRi5zZXJ2aWNlLkF1dGgoKTtcbiAqICAgICAgYXV0aC5sb2dpbih7IHVzZXJOYW1lOiAnanNtaXRoQGFjbWVzaW11bGF0aW9ucy5jb20nLFxuICogICAgICAgICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyB9KTtcbiAqICAgICAgYXV0aC5sb2dvdXQoKTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VyTmFtZTogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFzc3dvcmQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gUmVxdWlyZWQgaWYgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdhdXRoZW50aWNhdGlvbicpXG4gICAgfSk7XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvZ3MgdXNlciBpbiwgcmV0dXJuaW5nIHRoZSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAgICAgICAgICpcbiAgICAgICAgICogSWYgbm8gYHVzZXJOYW1lYCBvciBgcGFzc3dvcmRgIHdlcmUgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLCB0aGV5IGFyZSByZXF1aXJlZCBpbiB0aGUgYG9wdGlvbnNgIGhlcmUuIElmIG5vIGBhY2NvdW50YCB3YXMgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zIGFuZCB0aGUgYHVzZXJOYW1lYCBpcyBmb3IgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGUgYGFjY291bnRgIGlzIHJlcXVpcmVkIGFzIHdlbGwuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgYXV0aC5sb2dpbih7XG4gICAgICAgICAqICAgICAgICAgIHVzZXJOYW1lOiAnanNtaXRoJyxcbiAgICAgICAgICogICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcsXG4gICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyB9KVxuICAgICAgICAgKiAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhcInVzZXIgYWNjZXNzIHRva2VuIGlzOiBcIiwgdG9rZW4uYWNjZXNzX3Rva2VuKTtcbiAgICAgICAgICogICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHN1Y2Nlc3M6ICQubm9vcCB9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBpZiAoIWh0dHBPcHRpb25zLnVzZXJOYW1lIHx8ICFodHRwT3B0aW9ucy5wYXNzd29yZCkge1xuICAgICAgICAgICAgICAgIHZhciByZXNwID0geyBzdGF0dXM6IDQwMSwgc3RhdHVzTWVzc2FnZTogJ05vIHVzZXJuYW1lIG9yIHBhc3N3b3JkIHNwZWNpZmllZC4nIH07XG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvci5jYWxsKHRoaXMsIHJlc3ApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVqZWN0KHJlc3ApLnByb21pc2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHBvc3RQYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgdXNlck5hbWU6IGh0dHBPcHRpb25zLnVzZXJOYW1lLFxuICAgICAgICAgICAgICAgIHBhc3N3b3JkOiBodHRwT3B0aW9ucy5wYXNzd29yZCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoaHR0cE9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vcGFzcyBpbiBudWxsIGZvciBhY2NvdW50IHVuZGVyIG9wdGlvbnMgaWYgeW91IGRvbid0IHdhbnQgaXQgdG8gYmUgc2VudFxuICAgICAgICAgICAgICAgIHBvc3RQYXJhbXMuYWNjb3VudCA9IGh0dHBPcHRpb25zLmFjY291bnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocG9zdFBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2dzIHVzZXIgb3V0IGZyb20gc3BlY2lmaWVkIGFjY291bnRzLlxuICAgICAgICAgKiBFcGljZW50ZXIgbG9nb3V0IGlzIG5vdCBpbXBsZW1lbnRlZCB5ZXQsIGFkZGVkIGEgZHVtbXkgcHJvbWlzZSB0aGF0IGdldHMgYXV0b21hdGljYWxseSByZXNvbHZlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBhdXRoLmxvZ291dCgpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2dvdXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgZHRkLnJlc29sdmUoKTtcbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqICMjIENoYW5uZWwgU2VydmljZVxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBDaGFubmVsIFNlcnZpY2UgaXMgYSBidWlsZGluZyBibG9jayBmb3IgdGhpcyBmdW5jdGlvbmFsaXR5LiBJdCBjcmVhdGVzIGEgcHVibGlzaC1zdWJzY3JpYmUgb2JqZWN0LCBhbGxvd2luZyB5b3UgdG8gcHVibGlzaCBtZXNzYWdlcywgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzLCBvciB1bnN1YnNjcmliZSBmcm9tIG1lc3NhZ2VzIGZvciBhIGdpdmVuICd0b3BpYycgb24gYSBgJC5jb21ldGRgIHRyYW5zcG9ydCBpbnN0YW5jZS5cbiAqXG4gKiBUeXBpY2FsbHksIHlvdSB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgdG8gY3JlYXRlIG9yIHJldHJpZXZlIGNoYW5uZWxzLCB0aGVuIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gbGlzdGVuIHRvIG9yIHVwZGF0ZSBkYXRhLiAoRm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZCBvbiBFcGljZW50ZXIncyBwdXNoIGNoYW5uZWwsIHNlZSB0aGUgaW50cm9kdWN0b3J5IG5vdGVzIG9uIHRoZSBbUHVzaCBDaGFubmVsIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvKSBwYWdlLilcbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UuIFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLlxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCwgdGhlbiBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbiAqXG4gKiAgICAgICAgdmFyIGNzID0gbmV3IEYuc2VydmljZS5DaGFubmVsKCk7XG4gKiAgICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgU2VydmljZSBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgU2VydmljZS5cbiAqICogYG9wdGlvbnMuYmFzZWAgVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLnRvcGljUmVzb2x2ZXJgIEEgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgYWxsICd0b3BpY3MnIHBhc3NlZCBpbnRvIHRoZSBgcHVibGlzaGAgYW5kIGBzdWJzY3JpYmVgIG1ldGhvZHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGltcGxlbWVudCB5b3VyIG93biBzZXJpYWxpemUgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGN1c3RvbSBvYmplY3RzIHRvIHRvcGljIG5hbWVzLiBSZXR1cm5zIGEgU3RyaW5nLiBCeSBkZWZhdWx0LCBpdCBqdXN0IGVjaG9lcyB0aGUgdG9waWMuXG4gKiAqIGBvcHRpb25zLnRyYW5zcG9ydGAgVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLiBTZWUgaHR0cDovL2RvY3MuY29tZXRkLm9yZy9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gY29tZXRkLlxuICovXG52YXIgQ2hhbm5lbCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYmFzZSB0b3BpYy4gVGhpcyBpcyBhZGRlZCBhcyBhIHByZWZpeCB0byBhbGwgZnVydGhlciB0b3BpY3MgeW91IHB1Ymxpc2ggb3Igc3Vic2NyaWJlIHRvIHdoaWxlIHdvcmtpbmcgd2l0aCB0aGlzIENoYW5uZWwgU2VydmljZS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGJhc2U6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqIGB0b3BpY2AgVG9waWMgdG8gcGFyc2UuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiAqU3RyaW5nKjogVGhpcyBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIGEgc3RyaW5nIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICB0b3BpY1Jlc29sdmVyOiBmdW5jdGlvbiAodG9waWMpIHtcbiAgICAgICAgICAgIHJldHVybiB0b3BpYztcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiBudWxsXG4gICAgfTtcbiAgICB0aGlzLmNoYW5uZWxPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbn07XG5cbnZhciBtYWtlTmFtZSA9IGZ1bmN0aW9uIChjaGFubmVsTmFtZSwgdG9waWMpIHtcbiAgICAvL1JlcGxhY2UgdHJhaWxpbmcvZG91YmxlIHNsYXNoZXNcbiAgICB2YXIgbmV3TmFtZSA9IChjaGFubmVsTmFtZSA/IChjaGFubmVsTmFtZSArICcvJyArIHRvcGljKSA6IHRvcGljKS5yZXBsYWNlKC9cXC9cXC8vZywgJy8nKS5yZXBsYWNlKC9cXC8kLywnJyk7XG4gICAgcmV0dXJuIG5ld05hbWU7XG59O1xuXG5cbkNoYW5uZWwucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbC5wcm90b3R5cGUsIHtcblxuICAgIC8vIGZ1dHVyZSBmdW5jdGlvbmFsaXR5OlxuICAgIC8vICAgICAgLy8gU2V0IHRoZSBjb250ZXh0IGZvciB0aGUgY2FsbGJhY2tcbiAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgZnVuY3Rpb24gKCkgeyB0aGlzLmlubmVySFRNTCA9ICdUcmlnZ2VyZWQnfSwgZG9jdW1lbnQuYm9keSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gQ29udHJvbCB0aGUgb3JkZXIgb2Ygb3BlcmF0aW9ucyBieSBzZXR0aW5nIHRoZSBgcHJpb3JpdHlgXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4nLCBjYiwgdGhpcywge3ByaW9yaXR5OiA5fSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIDUwXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiA1MH0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBncmVhdGVyIHRoYW4gNTBcbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6ICc+NTAnfSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIGV2ZW5cbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6IGZ1bmN0aW9uICh2YWwpIHtyZXR1cm4gdmFsICUgMiA9PT0gMH19KTtcblxuXG4gICAgLyoqXG4gICAgICogU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqIFRoZSB0b3BpYyBzaG91bGQgaW5jbHVkZSB0aGUgZnVsbCBwYXRoIG9mIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cyksIHByb2plY3QgaWQsIGFuZCBncm91cCBuYW1lLiAoSW4gbW9zdCBjYXNlcywgaXQgaXMgc2ltcGxlciB0byB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgaW5zdGVhZCwgaW4gd2hpY2ggY2FzZSB0aGlzIGlzIGNvbmZpZ3VyZWQgZm9yIHlvdS4pXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlcyoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjYiA9IGZ1bmN0aW9uKHZhbCkgeyBjb25zb2xlLmxvZyh2YWwuZGF0YSk7IH07XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9wLWxldmVsICdydW4nIHRvcGljXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGNoaWxkcmVuIG9mIHRoZSAncnVuJyB0b3BpYy4gTm90ZSB0aGlzIHdpbGwgYWxzbyBiZSB0cmlnZ2VyZWQgZm9yIGNoYW5nZXMgdG8gcnVuLngueS56LlxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuLyonLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGJvdGggdGhlIHRvcC1sZXZlbCAncnVuJyB0b3BpYyBhbmQgaXRzIGNoaWxkcmVuXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoWycvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJyxcbiAgICAgKiAgICAgICAgICAnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJ10sIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSBwYXJ0aWN1bGFyIHZhcmlhYmxlXG4gICAgICogICAgICBzdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzL3ByaWNlJywgY2IpO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpTdHJpbmcqIFJldHVybnMgYSB0b2tlbiB5b3UgY2FuIGxhdGVyIHVzZSB0byB1bnN1YnNjcmliZS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfEFycmF5fSAgIGB0b3BpY2AgICAgTGlzdCBvZiB0b3BpY3MgdG8gbGlzdGVuIGZvciBjaGFuZ2VzIG9uLlxuICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBgY2FsbGJhY2tgIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGV4ZWN1dGUuIENhbGxiYWNrIGlzIGNhbGxlZCB3aXRoIHNpZ25hdHVyZSBgKGV2dCwgcGF5bG9hZCwgbWV0YWRhdGEpYC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgYGNvbnRleHRgICBDb250ZXh0IGluIHdoaWNoIHRoZSBgY2FsbGJhY2tgIGlzIGV4ZWN1dGVkLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gICBgb3B0aW9uc2AgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICogQHBhcmFtICB7TnVtYmVyfSAgIGBvcHRpb25zLnByaW9yaXR5YCAgVXNlZCB0byBjb250cm9sIG9yZGVyIG9mIG9wZXJhdGlvbnMuIERlZmF1bHRzIHRvIDAuIENhbiBiZSBhbnkgK3ZlIG9yIC12ZSBudW1iZXIuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE51bWJlcnxGdW5jdGlvbn0gICBgb3B0aW9ucy52YWx1ZWAgVGhlIGBjYWxsYmFja2AgaXMgb25seSB0cmlnZ2VyZWQgaWYgdGhpcyBjb25kaXRpb24gbWF0Y2hlcy4gU2VlIGV4YW1wbGVzIGZvciBkZXRhaWxzLlxuICAgICAqXG4gICAgICovXG4gICAgc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9waWMsIGNhbGxiYWNrLCBjb250ZXh0LCBvcHRpb25zKSB7XG5cbiAgICAgICAgdmFyIHRvcGljcyA9IFtdLmNvbmNhdCh0b3BpYyk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBzdWJzY3JpcHRpb25JZHMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuICAgICAgICBvcHRzLnRyYW5zcG9ydC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkLmVhY2godG9waWNzLCBmdW5jdGlvbiAoaW5kZXgsIHRvcGljKSB7XG4gICAgICAgICAgICAgICAgdG9waWMgPSBtYWtlTmFtZShvcHRzLmJhc2UsIG9wdHMudG9waWNSZXNvbHZlcih0b3BpYykpO1xuICAgICAgICAgICAgICAgIHN1YnNjcmlwdGlvbklkcy5wdXNoKG9wdHMudHJhbnNwb3J0LnN1YnNjcmliZSh0b3BpYywgY2FsbGJhY2spKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChzdWJzY3JpcHRpb25JZHNbMV0gPyBzdWJzY3JpcHRpb25JZHMgOiBzdWJzY3JpcHRpb25JZHNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBQdWJsaXNoIGRhdGEgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICAvLyBTZW5kIGRhdGEgdG8gYWxsIHN1YnNjcmliZXJzIG9mIHRoZSAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsIHsgY29tcGxldGVkOiBmYWxzZSB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bi92YXJpYWJsZXMnIHRvcGljXG4gICAgICogICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcycsIHsgcHJpY2U6IDUwIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRvcGljYCBUb3BpYyB0byBwdWJsaXNoIHRvLlxuICAgICAqIEBwYXJhbSAgeyp9IGBkYXRhYCAgRGF0YSB0byBwdWJsaXNoIHRvIHRvcGljLlxuICAgICAqXG4gICAgICovXG4gICAgcHVibGlzaDogZnVuY3Rpb24gKHRvcGljLCBkYXRhKSB7XG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgcmV0dXJuT2JqcyA9IFtdO1xuICAgICAgICB2YXIgb3B0cyA9IG1lLmNoYW5uZWxPcHRpb25zO1xuXG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBpZiAodG9waWMuY2hhckF0KHRvcGljLmxlbmd0aCAtIDEpID09PSAnKicpIHtcbiAgICAgICAgICAgICAgICAgICAgdG9waWMgPSB0b3BpYy5yZXBsYWNlKC9cXCorJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdZb3UgY2FuIGNhbm5vdCBwdWJsaXNoIHRvIGNoYW5uZWxzIHdpdGggd2lsZGNhcmRzLiBQdWJsaXNoaW5nIHRvICcsIHRvcGljLCAnaW5zdGVhZCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpzLnB1c2gob3B0cy50cmFuc3BvcnQucHVibGlzaCh0b3BpYywgZGF0YSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKHJldHVybk9ianNbMV0gPyByZXR1cm5PYmpzIDogcmV0dXJuT2Jqc1swXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVuc3Vic2NyaWJlIGZyb20gY2hhbmdlcyB0byBhIHRvcGljLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgY3MudW5zdWJzY3JpYmUoJ3NhbXBsZVRva2VuJyk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRva2VuYCBUaGUgdG9rZW4gZm9yIHRvcGljIGlzIHJldHVybmVkIHdoZW4geW91IGluaXRpYWxseSBzdWJzY3JpYmUuIFBhc3MgaXQgaGVyZSB0byB1bnN1YnNjcmliZSBmcm9tIHRoYXQgdG9waWMuXG4gICAgICovXG4gICAgdW5zdWJzY3JpYmU6IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICB0aGlzLmNoYW5uZWxPcHRpb25zLnRyYW5zcG9ydC51bnN1YnNjcmliZSh0b2tlbik7XG4gICAgICAgIHJldHVybiB0b2tlbjtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICpcbiAgICAgKiBTdXBwb3J0ZWQgZXZlbnRzIGFyZTogYGNvbm5lY3RgLCBgZGlzY29ubmVjdGAsIGBzdWJzY3JpYmVgLCBgdW5zdWJzY3JpYmVgLCBgcHVibGlzaGAsIGBlcnJvcmAuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqL1xuICAgIG9uOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vbi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdG9wIGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqL1xuICAgIG9mZjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub2ZmLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZXZlbnRzIGFuZCBleGVjdXRlIGhhbmRsZXJzLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqL1xuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENoYW5uZWw7XG4iLCIvKipcbiAqIEBjbGFzcyBDb25maWd1cmF0aW9uU2VydmljZVxuICpcbiAqIEFsbCBzZXJ2aWNlcyB0YWtlIGluIGEgY29uZmlndXJhdGlvbiBzZXR0aW5ncyBvYmplY3QgdG8gY29uZmlndXJlIHRoZW1zZWx2ZXMuIEEgSlMgaGFzaCB7fSBpcyBhIHZhbGlkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCBidXQgb3B0aW9uYWxseSB5b3UgY2FuIHVzZSB0aGUgY29uZmlndXJhdGlvbiBzZXJ2aWNlIHRvIHRvZ2dsZSBjb25maWdzIGJhc2VkIG9uIHRoZSBlbnZpcm9ubWVudFxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgdmFyIGNzID0gcmVxdWlyZSgnY29uZmlndXJhdGlvbi1zZXJ2aWNlJykoe1xuICogICAgICAgICAgZGV2OiB7IC8vZW52aXJvbm1lbnRcbiAgICAgICAgICAgICAgICBwb3J0OiAzMDAwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdsb2NhbGhvc3QnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHByb2Q6IHtcbiAgICAgICAgICAgICAgICBwb3J0OiA4MDgwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgICAgICAgICBsb2dMZXZlbDogJ25vbmUnXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbG9nTGV2ZWw6ICdERUJVRycgLy9nbG9iYWxcbiAqICAgICB9KTtcbiAqXG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudignZGV2Jyk7XG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudigncHJvZCcpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnbm9uZSdcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHVybFNlcnZpY2UgPSByZXF1aXJlKCcuL3VybC1jb25maWctc2VydmljZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IEVudmlyb25tZW50c1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgbG9nTGV2ZWw6ICdOT05FJ1xuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHNlcnZpY2VPcHRpb25zLnNlcnZlciA9IHVybFNlcnZpY2Uoc2VydmljZU9wdGlvbnMuc2VydmVyKTtcblxuICAgIHJldHVybiB7XG5cbiAgICAgICAgZGF0YTogc2VydmljZU9wdGlvbnMsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgZW52aXJvbm1lbnQga2V5IHRvIGdldCBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbVxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGVudlxuICAgICAgICAgKi9cbiAgICAgICAgc2V0RW52OiBmdW5jdGlvbiAoZW52KSB7XG5cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHByb3BlcnR5IG9wdGlvbmFsXG4gICAgICAgICAqIEByZXR1cm4geyp9ICAgICAgICAgIFZhbHVlIG9mIHByb3BlcnR5IGlmIHNwZWNpZmllZCwgdGhlIGVudGlyZSBjb25maWcgb2JqZWN0IG90aGVyd2lzZVxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9uc1twcm9wZXJ0eV07XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5IGlmIGEga2V5IGlzIHByb3ZpZGVkLCBzZXQgYSBrZXkgdG8gdGhhdCB2YWx1ZS4gT3RoZXJ3aXNlIG1lcmdlIG9iamVjdCB3aXRoIGN1cnJlbnQgY29uZmlnXG4gICAgICAgICAqIEBwYXJhbSAgeyp9IHZhbHVlICB2YWx1ZSBmb3IgcHJvdmlkZWQga2V5XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9uc1trZXldID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9O1xufTtcblxuIiwiLyoqXG4gKiAjI0RhdGEgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgRGF0YSBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgbWFuaXB1bGF0ZSBkYXRhIHJlbGF0ZWQgdG8gYW55IG9mIHlvdXIgcHJvamVjdHMuIERhdGEgYXJlIG9yZ2FuaXplZCBpbiBjb2xsZWN0aW9ucy4gRWFjaCBjb2xsZWN0aW9uIGNvbnRhaW5zIGEgZG9jdW1lbnQ7IGVhY2ggZWxlbWVudCBvZiB0aGlzIHRvcC1sZXZlbCBkb2N1bWVudCBpcyBhIEpTT04gb2JqZWN0LiAoU2VlIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gb24gdGhlIHVuZGVybHlpbmcgW0RhdGEgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvZGF0YV9hcGkvKS4pXG4gKlxuICogQWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgRGF0YSBBUEkgU2VydmljZSBkZWZhdWx0cy4gSW4gcGFydGljdWxhciwgdGhlcmUgYXJlIHRocmVlIHJlcXVpcmVkIHBhcmFtZXRlcnMgd2hlbiB5b3UgaW5zdGFudGlhdGUgdGhlIERhdGEgU2VydmljZTpcbiAqXG4gKiAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgcHJvamVjdGA6IEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICogKiBgcm9vdGA6IFRoZSB0aGUgbmFtZSBvZiB0aGUgY29sbGVjdGlvbi4gSWYgeW91IGhhdmUgbXVsdGlwbGUgY29sbGVjdGlvbnMgd2l0aGluIGVhY2ggb2YgeW91ciBwcm9qZWN0cywgeW91IGNhbiBhbHNvIHBhc3MgdGhlIGNvbGxlY3Rpb24gbmFtZSBhcyBhbiBvcHRpb24gZm9yIGVhY2ggY2FsbC5cbiAqXG4gKiAgICAgICB2YXIgZHMgPSBuZXcgRi5zZXJ2aWNlLkRhdGEoe1xuICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgIHJvb3Q6ICdzdXJ2ZXktcmVzcG9uc2VzJyxcbiAqICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBkcy5zYXZlQXMoJ3VzZXIxJyxcbiAqICAgICAgICAgIHsgJ3F1ZXN0aW9uMSc6IDIsICdxdWVzdGlvbjInOiAxMCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiBmYWxzZSwgJ3F1ZXN0aW9uNCc6ICdzb21ldGltZXMnIH0gKTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjInLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMywgJ3F1ZXN0aW9uMic6IDgsXG4gKiAgICAgICAgICAncXVlc3Rpb24zJzogdHJ1ZSwgJ3F1ZXN0aW9uNCc6ICdhbHdheXMnIH0gKTtcbiAqICAgICAgIGRzLnF1ZXJ5KCcnLHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICpcbiAqIE5vdGUgdGhhdCBpbiBhZGRpdGlvbiB0byB0aGUgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgcm9vdGAsIHRoZSBEYXRhIFNlcnZpY2UgcGFyYW1ldGVycyBvcHRpb25hbGx5IGluY2x1ZGUgYSBgc2VydmVyYCBvYmplY3QsIHdob3NlIGBob3N0YCBmaWVsZCBjb250YWlucyB0aGUgVVJJIG9mIHRoZSBGb3JpbyBzZXJ2ZXIuIFRoaXMgaXMgYXV0b21hdGljYWxseSBzZXQsIGJ1dCB5b3UgY2FuIHBhc3MgaXQgZXhwbGljaXRseSBpZiBkZXNpcmVkLiBJdCBpcyBtb3N0IGNvbW1vbmx5IHVzZWQgZm9yIGNsYXJpdHkgd2hlbiB5b3UgYXJlIFtob3N0aW5nIGFuIEVwaWNlbnRlciBwcm9qZWN0IG9uIHlvdXIgb3duIHNlcnZlcl0oLi4vLi4vLi4vaG93X3RvL3NlbGZfaG9zdGluZy8pLlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogTmFtZSBvZiBjb2xsZWN0aW9uLiBEZWZhdWx0cyB0byBgL2AsIHRoYXQgaXMsIHRoZSByb290IGxldmVsIG9mIHlvdXIgcHJvamVjdCBhdCBgZm9yaW8uY29tL2FwcC95b3VyLWFjY291bnQtaWQveW91ci1wcm9qZWN0LWlkL2AuIFJlcXVpcmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcm9vdDogJy8nLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIG9wZXJhdGlvbnMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIGRvbWFpbjogJ2ZvcmlvLmNvbScsXG5cbiAgICAgICAgLy9PcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoa2V5LCByb290KSB7XG4gICAgICAgIGlmICghcm9vdCkge1xuICAgICAgICAgICAgcm9vdCA9IHNlcnZpY2VPcHRpb25zLnJvb3Q7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdkYXRhJykgKyBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKHJvb3QpO1xuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICB1cmwrPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBUaGUgbmFtZSBvZiB0aGUgZG9jdW1lbnQgdG8gc2VhcmNoLiBQYXNzIHRoZSBlbXB0eSBzdHJpbmcgKCcnKSB0byBzZWFyY2ggdGhlIGVudGlyZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHF1ZXJ5YCBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgdG8gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHtxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBrZXlgIElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWx1ZWAgKE9wdGlvbmFsKSBUaGUgZGF0YSB0byBzYXZlLiBJZiBga2V5YCBpcyBhIHN0cmluZywgdGhpcyBpcyB0aGUgdmFsdWUgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgdmFsdWUocykgdG8gc2F2ZSBhcmUgYWxyZWFkeSBwYXJ0IG9mIGBrZXlgIGFuZCB0aGlzIGFyZ3VtZW50IGlzIG5vdCByZXF1aXJlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhIG5hbWVkIGRvY3VtZW50IG9yIGVsZW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHNlcGFyYXRlbHkgaW4gY29uZmlndXJhdGlvbiBvcHRpb25zLCBlaXRoZXIgYXMgcGFydCBvZiB0aGUgY2FsbCBvciBhcyBwYXJ0IG9mIHRoZSBpbml0aWFsaXphdGlvbiBvZiBkcy5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYGtleWAgSWQgb2YgdGhlIGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYGtleWAgVGhlIGlkIG9mIHRoZSBkYXRhIHRvIHJldHVybi4gQ2FuIGJlIHRoZSBpZCBvZiBhIGRvY3VtZW50LCBvciBhIHBhdGggdG8gZGF0YSB3aXRoaW4gdGhhdCBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChrZXksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBkYXRhIGZyb20gY29sbGVjdGlvbi4gT25seSBkb2N1bWVudHMgKHRvcC1sZXZlbCBlbGVtZW50cyBpbiBlYWNoIGNvbGxlY3Rpb24pIGNhbiBiZSBkZWxldGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgZHMucmVtb3ZlKCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xBcnJheX0gYGtleXNgIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBwYXJhbXM7XG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KGtleXMpKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBpZDoga2V5cyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSAnJztcbiAgICAgICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5cywgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFcGljZW50ZXIgZG9lc24ndCBhbGxvdyBudWtpbmcgY29sbGVjdGlvbnNcbiAgICAgICAgLy8gICAgIC8qKlxuICAgICAgICAvLyAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgLy8gICAgICAqIEByZXR1cm4gbnVsbFxuICAgICAgICAvLyAgICAgICovXG4gICAgICAgIC8vICAgICBkZXN0cm95OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgnJywgb3B0aW9ucyk7XG4gICAgICAgIC8vICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyNNZW1iZXIgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgTWVtYmVyIEFQSSBBZGFwdGVyIHByb3ZpZGVzIG1ldGhvZHMgdG8gbG9vayB1cCBpbmZvcm1hdGlvbiBhYm91dCBlbmQgdXNlcnMgZm9yIHlvdXIgcHJvamVjdCBhbmQgaG93IHRoZXkgYXJlIGRpdmlkZWQgYWNyb3NzIGdyb3Vwcy4gSXQgaXMgYmFzZWQgb24gcXVlcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW01lbWJlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvbWVtYmVyLykuXG4gKlxuICogVGhpcyBpcyBvbmx5IG5lZWRlZCBmb3IgQXV0aGVudGljYXRlZCBwcm9qZWN0cywgdGhhdCBpcywgdGVhbSBwcm9qZWN0cyB3aXRoIFtlbmQgdXNlcnMgYW5kIGdyb3Vwc10oLi4vLi4vLi4vZ3JvdXBzX2FuZF9lbmRfdXNlcnMvKS4gRm9yIGV4YW1wbGUsIGlmIHNvbWUgb2YgeW91ciBlbmQgdXNlcnMgYXJlIGZhY2lsaXRhdG9ycywgb3IgaWYgeW91ciBlbmQgdXNlcnMgc2hvdWxkIGJlIHRyZWF0ZWQgZGlmZmVyZW50bHkgYmFzZWQgb24gd2hpY2ggZ3JvdXAgdGhleSBhcmUgaW4sIHVzZSB0aGUgTWVtYmVyIEFQSSB0byBmaW5kIHRoYXQgaW5mb3JtYXRpb24uXG4gKlxuICogICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gKiAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICdiNmIzMTNhMy1hYjg0LTQ3OWMtYmFlYS0yMDZmNmJmZjMzNycgfSk7XG4gKiAgICAgIG1hLmdldEdyb3VwRGV0YWlscyh7IGdyb3VwSWQ6ICcwMGI1MzMwOC05ODMzLTQ3ZjItYjIxZS0xMjc4YzA3ZDUzYjgnIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGFwaUVuZHBvaW50ID0gJ21lbWJlci9sb2NhbCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciB1c2VyIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBncm91cCBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuIE5vdGUgdGhhdCB0aGlzIGlzIHRoZSBncm91cCAqaWQqLCBub3QgdGhlIGdyb3VwICpuYW1lKi5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGdyb3VwSWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucywgc2VydmljZU9wdGlvbnMpO1xuXG4gICAgdmFyIGdldEZpbmFsUGFyYW1zID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBwYXRjaFVzZXJBY3RpdmVGaWVsZCA9IGZ1bmN0aW9uIChwYXJhbXMsIGFjdGl2ZSwgb3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBwYXJhbXMuZ3JvdXBJZCArICcvJyArIHBhcmFtcy51c2VySWRcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goeyBhY3RpdmU6IGFjdGl2ZSB9LCBodHRwT3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBhbGwgb2YgdGhlIGdyb3VwIG1lbWJlcnNoaXBzIGZvciBvbmUgZW5kIHVzZXIuIFRoZSBtZW1iZXJzaGlwIGRldGFpbHMgYXJlIHJldHVybmVkIGluIGFuIGFycmF5LCB3aXRoIG9uZSBlbGVtZW50IChncm91cCByZWNvcmQpIGZvciBlYWNoIGdyb3VwIHRvIHdoaWNoIHRoZSBlbmQgdXNlciBiZWxvbmdzLlxuICAgICAgICAqXG4gICAgICAgICogSW4gdGhlIG1lbWJlcnNoaXAgYXJyYXksIGVhY2ggZ3JvdXAgcmVjb3JkIGluY2x1ZGVzIHRoZSBncm91cCBpZCwgcHJvamVjdCBpZCwgYWNjb3VudCAodGVhbSkgaWQsIGFuZCBhbiBhcnJheSBvZiBtZW1iZXJzLiBIb3dldmVyLCBvbmx5IHRoZSB1c2VyIHdob3NlIHVzZXJJZCBpcyBpbmNsdWRlZCBpbiB0aGUgY2FsbCBpcyBsaXN0ZWQgaW4gdGhlIG1lbWJlcnMgYXJyYXkgKHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGVyZSBhcmUgb3RoZXIgbWVtYmVycyBpbiB0aGlzIGdyb3VwKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcignNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24obWVtYmVyc2hpcHMpe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPG1lbWJlcnNoaXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cobWVtYmVyc2hpcHNbaV0uZ3JvdXBJZCk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gYHBhcmFtc2AgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlci4gQWx0ZXJuYXRpdmVseSwgYW4gb2JqZWN0IHdpdGggZmllbGQgYHVzZXJJZGAgYW5kIHZhbHVlIHRoZSB1c2VyIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRHcm91cHNGb3JVc2VyOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB1c2VySWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ2V0UGFybXMgPSBpc1N0cmluZyA/IHsgdXNlcklkOiBwYXJhbXMgfSA6IF9waWNrKG9ialBhcmFtcywgJ3VzZXJJZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldFBhcm1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBvbmUgZ3JvdXAsIGluY2x1ZGluZyBhbiBhcnJheSBvZiBhbGwgaXRzIG1lbWJlcnMuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3VwRGV0YWlscygnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZ3JvdXApe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPGdyb3VwLm1lbWJlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhncm91cC5tZW1iZXJzW2ldLnVzZXJOYW1lKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIH1cbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoeyBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fSBgcGFyYW1zYCBUaGUgZ3JvdXAgaWQuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGBncm91cElkYCBhbmQgdmFsdWUgdGhlIGdyb3VwIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0R3JvdXBEZXRhaWxzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMuZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZ3JvdXBJZCBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBncm91cElkID0gaXNTdHJpbmcgPyBwYXJhbXMgOiBvYmpQYXJhbXMuZ3JvdXBJZDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIGdyb3VwSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgYWN0aXZlYC4gQWN0aXZlIGVuZCB1c2VycyBjYW4gYmUgYXNzaWduZWQgdG8gW3dvcmxkc10oLi4vd29ybGQtbWFuYWdlci8pIGluIG11bHRpcGxheWVyIGdhbWVzIGR1cmluZyBhdXRvbWF0aWMgYXNzaWdubWVudC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEubWFrZVVzZXJBY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIG1ha2VVc2VyQWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCB0cnVlLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBTZXQgYSBwYXJ0aWN1bGFyIGVuZCB1c2VyIGFzIGBpbmFjdGl2ZWAuIEluYWN0aXZlIGVuZCB1c2VycyBhcmUgbm90IGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VySW5hY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggdGhpcyBlbmQgdXNlciBiZWxvbmdzLCBhbmQgaW4gd2hpY2ggdGhlIGVuZCB1c2VyIHNob3VsZCBiZWNvbWUgaW5hY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckluYWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCBmYWxzZSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI1J1biBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBSdW4gQVBJIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBwZXJmb3JtIGNvbW1vbiB0YXNrcyBhcm91bmQgY3JlYXRpbmcgYW5kIHVwZGF0aW5nIHJ1bnMsIHZhcmlhYmxlcywgYW5kIGRhdGEuXG4gKlxuICogV2hlbiBidWlsZGluZyBpbnRlcmZhY2VzIHRvIHNob3cgcnVuIG9uZSBhdCBhIHRpbWUgKGFzIGZvciBzdGFuZGFyZCBlbmQgdXNlcnMpLCB0eXBpY2FsbHkgeW91IGZpcnN0IGluc3RhbnRpYXRlIGEgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGFuZCB0aGVuIGFjY2VzcyB0aGUgUnVuIFNlcnZpY2UgdGhhdCBpcyBhdXRvbWF0aWNhbGx5IHBhcnQgb2YgdGhlIG1hbmFnZXIsIHJhdGhlciB0aGFuIGluc3RhbnRpYXRpbmcgdGhlIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LiBUaGlzIGlzIGJlY2F1c2UgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLlxuICpcbiAqIEhvd2V2ZXIsIG1hbnkgb2YgdGhlIEVwaWNlbnRlciBzYW1wbGUgcHJvamVjdHMgdXNlIGEgUnVuIFNlcnZpY2UsIGJlY2F1c2UgZ2VuZXJhbGx5IHRoZSBzYW1wbGUgcHJvamVjdHMgYXJlIHBsYXllZCBpbiBvbmUgZW5kIHVzZXIgc2Vzc2lvbiBhbmQgZG9uJ3QgY2FyZSBhYm91dCBydW4gc3RhdGVzIG9yIFtydW4gc3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKS4gVGhlIFJ1biBBUEkgU2VydmljZSBpcyBhbHNvIHVzZWZ1bCBmb3IgYnVpbGRpbmcgYW4gaW50ZXJmYWNlIGZvciBhIGZhY2lsaXRhdG9yLCBiZWNhdXNlIGl0IG1ha2VzIGl0IGVhc3kgdG8gbGlzdCBkYXRhIGFjcm9zcyBtdWx0aXBsZSBydW5zICh1c2luZyB0aGUgYGZpbHRlcigpYCBhbmQgYHF1ZXJ5KClgIG1ldGhvZHMpLlxuICpcbiAqIFRvIHVzZSB0aGUgUnVuIEFQSSBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKlxuICogRm9yIGV4YW1wbGUsXG4gKlxuICogICAgICAgdmFyIHJzID0gbmV3IEYuc2VydmljZS5SdW4oe1xuICogICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgIH0pO1xuICogICAgICBycy5jcmVhdGUoJ3N1cHBseV9jaGFpbl9nYW1lLnB5JykudGhlbihmdW5jdGlvbihydW4pIHtcbiAqICAgICAgICAgICAgIHJzLmRvKCdzb21lT3BlcmF0aW9uJyk7XG4gKiAgICAgIH0pO1xuICpcbiAqXG4gKiBBZGRpdGlvbmFsbHksIGFsbCBBUEkgY2FsbHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFJ1biBBUEkgU2VydmljZSBkZWZhdWx0cyBsaXN0ZWQgYmVsb3cuXG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGBtb2RlbGAsIHRoZSBSdW4gU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKlxuICogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiAqICAgICAgICAgICBydW46IHtcbiAqICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseV9jaGFpbl9nYW1lLnB5JyxcbiAqICAgICAgICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICAgICAgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBybS5nZXRSdW4oKVxuICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBSdW4gU2VydmljZSxcbiAqICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4gKiAgICAgICAgICAgICAgIHZhciBycyA9IHJtLnJ1bjtcbiAqICAgICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgIH0pXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgVmFyaWFibGVzU2VydmljZSA9IHJlcXVpcmUoJy4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8IHN0b3JlLmdldCgnZXBpY2VudGVyLnRva2VuJykgfHwgJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgcnVucy4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlci5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRmxhZyBkZXRlcm1pbmVzIGlmIGBYLUF1dG9SZXN0b3JlOiB0cnVlYCBoZWFkZXIgaXMgc2VudCB0byBFcGljZW50ZXIuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBhdXRvUmVzdG9yZTogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuICAgIHVybENvbmZpZy5nZXRGaWx0ZXJVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJyk7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBxdXRpbC50b01hdHJpeEZvcm1hdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpO1xuXG4gICAgICAgIGlmIChmaWx0ZXIpIHtcbiAgICAgICAgICAgIHVybCArPSBmaWx0ZXIgKyAnLyc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmZpbHRlcjtcbiAgICAgICAgLy8gVGhlIHNlbWljb2xvbiBzZXBhcmF0ZWQgZmlsdGVyIGlzIHVzZWQgd2hlbiBmaWx0ZXIgaXMgYW4gb2JqZWN0XG4gICAgICAgIHZhciBpc0ZpbHRlclJ1bklkID0gZmlsdGVyICYmICQudHlwZShmaWx0ZXIpID09PSAnc3RyaW5nJztcbiAgICAgICAgaWYgKHNlcnZpY2VPcHRpb25zLmF1dG9SZXN0b3JlICYmIGlzRmlsdGVyUnVuSWQpIHtcbiAgICAgICAgICAgIC8vIEJ5IGRlZmF1bHQgYXV0b3JlcGxheSB0aGUgcnVuIGJ5IHNlbmRpbmcgdGhpcyBoZWFkZXIgdG8gZXBpY2VudGVyXG4gICAgICAgICAgICAvLyBodHRwczovL2ZvcmlvLmNvbS9lcGljZW50ZXIvZG9jcy9wdWJsaWMvcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNyZXRyaWV2aW5nXG4gICAgICAgICAgICB2YXIgYXV0b3Jlc3RvcmVPcHRzID0ge1xuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJ1gtQXV0b1Jlc3RvcmUnOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBhdXRvcmVzdG9yZU9wdHMsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgc2V0RmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBmaWx0ZXIgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgdXJsQ29uZmlnOiB1cmxDb25maWcsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyZWF0ZSBhIG5ldyBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIE5PVEU6IFR5cGljYWxseSB0aGlzIGlzIG5vdCB1c2VkISBVc2UgYFJ1bk1hbmFnZXIuZ2V0UnVuKClgIHdpdGggYSBgc3RyYXRlZ3lgIG9mIGBhbHdheXMtbmV3YCwgb3IgdXNlIGBSdW5NYW5hZ2VyLnJlc2V0KClgLiBTZWUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHJzLmNyZWF0ZSgnaGVsbG9fd29ybGQuamwnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYHBhcmFtc2AgSWYgYSBzdHJpbmcsIHRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IFttb2RlbCBmaWxlXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4gVGhpcyBpcyB0aGUgb25lIGZpbGUgaW4gdGhlIHByb2plY3QgdGhhdCBleHBsaWNpdGx5IGV4cG9zZXMgdmFyaWFibGVzIGFuZCBtZXRob2RzLCBhbmQgaXQgbXVzdCBiZSBzdG9yZWQgaW4gdGhlIE1vZGVsIGZvbGRlciBvZiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBJZiBhbiBvYmplY3QsIG1heSBpbmNsdWRlIGBtb2RlbGAsIGBzY29wZWAsIGFuZCBgZmlsZXNgLiAoU2VlIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bl9tYW5hZ2VyLykgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gYHNjb3BlYCBhbmQgYGZpbGVzYC4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICpcbiAgICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJykgfSk7XG4gICAgICAgICAgICB2YXIgcnVuQXBpUGFyYW1zID0gWydtb2RlbCcsICdzY29wZScsICdmaWxlcyddO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gdGhpcyBpcyBqdXN0IHRoZSBtb2RlbCBuYW1lXG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBtb2RlbDogcGFyYW1zIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHdoaXRlbGlzdCB0aGUgZmllbGRzIHRoYXQgd2UgYWN0dWFsbHkgY2FuIHNlbmQgdG8gdGhlIGFwaVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgcnVuQXBpUGFyYW1zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGVsZW1lbnRzIG9mIHRoZSBgcXNgIG9iamVjdCBhcmUgQU5EZWQgdG9nZXRoZXIgd2l0aGluIGEgc2luZ2xlIGNhbGwgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZXR1cm5zIHJ1bnMgd2l0aCBzYXZlZCA9IHRydWUgYW5kIHZhcmlhYmxlcy5wcmljZSA+IDEsXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgdmFyaWFibGVzLnByaWNlIGhhcyBiZWVuIHBlcnNpc3RlZCAocmVjb3JkZWQpXG4gICAgICAgICAqICAgICAgLy8gaW4gdGhlIG1vZGVsLlxuICAgICAgICAgKiAgICAgcnMucXVlcnkoe1xuICAgICAgICAgKiAgICAgICAgICAnc2F2ZWQnOiAndHJ1ZScsXG4gICAgICAgICAqICAgICAgICAgICcucHJpY2UnOiAnPjEnXG4gICAgICAgICAqICAgICAgIH0sXG4gICAgICAgICAqICAgICAgIHtcbiAgICAgICAgICogICAgICAgICAgc3RhcnRyZWNvcmQ6IDIsXG4gICAgICAgICAqICAgICAgICAgIGVuZHJlY29yZDogNVxuICAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBxc2AgUXVlcnkgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBRdWVyeWluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXMsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBxczsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFNpbWlsYXIgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJgIEZpbHRlciBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIEZpbHRlcmluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogZnVuY3Rpb24gKGZpbHRlciwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qoc2VydmljZU9wdGlvbnMuZmlsdGVyKSkge1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlcnZpY2VPcHRpb25zLmZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gZmlsdGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBkYXRhIGZvciBhIHNwZWNpZmljIHJ1bi4gVGhpcyBpbmNsdWRlcyBzdGFuZGFyZCBydW4gZGF0YSBzdWNoIGFzIHRoZSBhY2NvdW50LCBtb2RlbCwgcHJvamVjdCwgYW5kIGNyZWF0ZWQgYW5kIGxhc3QgbW9kaWZpZWQgZGF0ZXMuIFRvIHJlcXVlc3Qgc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLCBwYXNzIHRoZW0gYXMgcGFydCBvZiB0aGUgYGZpbHRlcnNgIHBhcmFtZXRlci5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IGlmIHRoZSBydW4gaXMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSksIGFueSBtb2RlbCB2YXJpYWJsZXMgYXJlIGF2YWlsYWJsZTsgaWYgdGhlIHJ1biBpcyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLCBvbmx5IG1vZGVsIHZhcmlhYmxlcyB0aGF0IGhhdmUgYmVlbiBwZXJzaXN0ZWQgJm1kYXNoOyB0aGF0IGlzLCBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwgJm1kYXNoOyBhcmUgYXZhaWxhYmxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgcnMubG9hZCgnYmI1ODk2NzctZDQ3Ni00OTcxLWE2OGUtMGM1OGQxOTFlNDUwJywgeyBpbmNsdWRlOiBbJy5wcmljZScsICcuc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBydW5JRGAgVGhlIHJ1biBpZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJzYCAoT3B0aW9uYWwpIE9iamVjdCBjb250YWluaW5nIGZpbHRlcnMgYW5kIG9wZXJhdGlvbiBtb2RpZmllcnMuIFVzZSBrZXkgYGluY2x1ZGVgIHRvIGxpc3QgbW9kZWwgdmFyaWFibGVzIHRoYXQgeW91IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUgcmVzcG9uc2UuIE90aGVyIGF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAocnVuSUQsIGZpbHRlcnMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmIChydW5JRCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJ1bklEOyAvL3Nob3VsZG4ndCBiZSBhYmxlIHRvIG92ZXItcmlkZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBhdHRyaWJ1dGVzIChkYXRhLCBtb2RlbCB2YXJpYWJsZXMpIG9mIHRoZSBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gYWRkICdjb21wbGV0ZWQnIGZpZWxkIHRvIHJ1biByZWNvcmRcbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBjb21wbGV0ZWQ6IHRydWUgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyB1cGRhdGUgJ3NhdmVkJyBmaWVsZCBvZiBydW4gcmVjb3JkLCBhbmQgdXBkYXRlIHZhbHVlcyBvZiBtb2RlbCB2YXJpYWJsZXMgZm9yIHRoaXMgcnVuXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgc2F2ZWQ6IHRydWUsIHZhcmlhYmxlczogeyBhOiAyMywgYjogMjMgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBhdHRyaWJ1dGVzYCBUaGUgcnVuIGRhdGEgYW5kIHZhcmlhYmxlcyB0byBzYXZlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGF0dHJpYnV0ZXMudmFyaWFibGVzYCBNb2RlbCB2YXJpYWJsZXMgbXVzdCBiZSBpbmNsdWRlZCBpbiBhIGB2YXJpYWJsZXNgIGZpZWxkIHdpdGhpbiB0aGUgYGF0dHJpYnV0ZXNgIG9iamVjdC4gKE90aGVyd2lzZSB0aGV5IGFyZSB0cmVhdGVkIGFzIHJ1biBkYXRhIGFuZCBhZGRlZCB0byB0aGUgcnVuIHJlY29yZCBkaXJlY3RseS4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uIChhdHRyaWJ1dGVzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKGF0dHJpYnV0ZXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBhIG1ldGhvZCBmcm9tIHRoZSBtb2RlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2QgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGBwYXJhbXNgIGFyZ3VtZW50IGlzIG5vcm1hbGx5IGFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byB0aGUgYG9wZXJhdGlvbmAuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXkuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCB5b3UgY2FuIGNvbWJpbmUgdGhlIGBvcGVyYXRpb25gIGFuZCBgcGFyYW1zYCBhcmd1bWVudHMgaW50byBhIHNpbmdsZSBvYmplY3QgaWYgeW91IHByZWZlciwgYXMgaW4gdGhlIGxhc3QgZXhhbXBsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic29sdmVcIiB0YWtlcyBubyBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLmRvKCdzb2x2ZScpO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsIFsnaGVsbG8nXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgJ2hlbGxvJyk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic3VtQXJyYXlcIiB0YWtlcyBvbmUgYXJndW1lbnQsIGFuIGFycmF5XG4gICAgICAgICAqICAgICBycy5kbygnc3VtQXJyYXknLCBbWzQsMiwxXV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImFkZFwiIHRha2VzIHR3byBhcmd1bWVudHMsIGJvdGggaW50ZWdlcnNcbiAgICAgICAgICogICAgIHJzLmRvKHsgbmFtZTonYWRkJywgcGFyYW1zOlsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYG9wZXJhdGlvbmAgTmFtZSBvZiBtZXRob2QuXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBwYXJhbXNgIChPcHRpb25hbCkgQW55IHBhcmFtZXRlcnMgdGhlIG9wZXJhdGlvbiB0YWtlcywgcGFzc2VkIGFzIGFuIGFycmF5LiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LCBhbmQgY2FuIGp1c3QgcGFzcyBpdCBkaXJlY3RseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZG86IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ2RvJywgb3BlcmF0aW9uLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wc0FyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnM7XG4gICAgICAgICAgICBpZiAob3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICAgICAgb3BzQXJncyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9uLCBvcHNBcmdzKTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgcG9zdE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcHJtcyA9IChyZXN1bHQuYXJnc1swXS5sZW5ndGggJiYgKHJlc3VsdC5hcmdzWzBdICE9PSBudWxsICYmIHJlc3VsdC5hcmdzWzBdICE9PSB1bmRlZmluZWQpKSA/IHJlc3VsdC5hcmdzWzBdIDogW107XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgYXJndW1lbnRzOiBwcm1zIH0sICQuZXh0ZW5kKHRydWUsIHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ29wZXJhdGlvbnMvJyArIHJlc3VsdC5vcHNbMF0gKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwsIHNlcXVlbnRpYWxseS5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2RzIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0aWFsaXplXCIgYW5kIFwic29sdmVcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWydpbml0aWFsaXplJywgJ3NvbHZlJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0XCIgYW5kIFwicmVzZXRcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncmVzZXQnLCBwYXJhbXM6IFsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJpbml0XCIgdGFrZXMgdHdvIGFyZ3VtZW50cyxcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJydW5tb2RlbFwiIHRha2VzIG5vbmVcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3J1bm1vZGVsJywgcGFyYW1zOiBbXSB9XSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBvcGVyYXRpb25zYCBJZiBub25lIG9mIHRoZSBtZXRob2RzIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgbWV0aG9kIG5hbWVzIChzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBtZXRob2RzIGRvIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGEgbWV0aG9kIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzZXJpYWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9TaW5nbGVPcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgb3AgPSBvcHMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICB2YXIgYXJnID0gYXJncy5zaGlmdCgpO1xuXG4gICAgICAgICAgICAgICAgbWUuZG8ob3AsIGFyZywge1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob3BzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbCwgZXhlY3V0aW5nIHRoZW0gaW4gcGFyYWxsZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kcyBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJzb2x2ZVwiIGFuZCBcInJlc2V0XCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWydzb2x2ZScsICdyZXNldCddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWyB7IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3N1YnRyYWN0JywgcGFyYW1zOlsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoeyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fSBgb3BlcmF0aW9uc2AgSWYgbm9uZSBvZiB0aGUgbWV0aG9kcyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG1ldGhvZCBuYW1lcyAoYXMgc3RyaW5ncykuIElmIGFueSBvZiB0aGUgbWV0aG9kcyBkbyB0YWtlIHBhcmFtZXRlcnMsIHlvdSBoYXZlIHR3byBvcHRpb25zLiBZb3UgY2FuIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhIG1ldGhvZCBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBwYXNzIGEgc2luZ2xlIG9iamVjdCB3aXRoIHRoZSBtZXRob2QgbmFtZSBhbmQgYSAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFsbGVsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG5cbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcXVldWUgID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaTwgb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcXVldWUucHVzaChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kbyhvcHNbaV0sIGFyZ3NbaV0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICQud2hlbi5hcHBseSh0aGlzLCBxdWV1ZSlcbiAgICAgICAgICAgICAgICAuZG9uZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2Vzcy5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvci5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY1N5bmNBUEkgPSB7XG4gICAgICAgIGdldEN1cnJlbnRDb25maWc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgfSxcbiAgICAgICAgLyoqXG4gICAgICAgICAgKiBSZXR1cm5zIGEgVmFyaWFibGVzIFNlcnZpY2UgaW5zdGFuY2UuIFVzZSB0aGUgdmFyaWFibGVzIGluc3RhbmNlIHRvIGxvYWQsIHNhdmUsIGFuZCBxdWVyeSBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLiBTZWUgdGhlIFtWYXJpYWJsZSBBUEkgU2VydmljZV0oLi4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAgICAgICAgKlxuICAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAgICAgIHZhciB2cyA9IHJzLnZhcmlhYmxlcygpO1xuICAgICAgICAgICogICAgICB2cy5zYXZlKHsgc2FtcGxlX2ludDogNCB9KTtcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBjb25maWdgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAgKi9cbiAgICAgICAgdmFyaWFibGVzOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgdnMgPSBuZXcgVmFyaWFibGVzU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZywge1xuICAgICAgICAgICAgICAgIHJ1blNlcnZpY2U6IHRoaXNcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIHJldHVybiB2cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljU3luY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4gKiAjI1N0YXRlIEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIFN0YXRlIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gcmVwbGF5IG9yIGNsb25lIHJ1bnMuIEl0IGJyaW5ncyBleGlzdGluZywgcGVyc2lzdGVkIHJ1biBkYXRhIGZyb20gdGhlIGRhdGFiYXNlIGJhY2sgaW50byBtZW1vcnksIHVzaW5nIHRoZSBzYW1lIHJ1biBpZCAoYHJlcGxheWApIG9yIGEgbmV3IHJ1biBpZCAoYGNsb25lYCkuIFJ1bnMgbXVzdCBiZSBpbiBtZW1vcnkgaW4gb3JkZXIgZm9yIHlvdSB0byB1cGRhdGUgdmFyaWFibGVzIG9yIGNhbGwgb3BlcmF0aW9ucyBvbiB0aGVtLlxuICpcbiAqIFNwZWNpZmljYWxseSwgdGhlIFN0YXRlIEFQSSBBZGFwdGVyIHdvcmtzIGJ5IFwicmUtcnVubmluZ1wiIHRoZSBydW4gKHVzZXIgaW50ZXJhY3Rpb25zKSBmcm9tIHRoZSBjcmVhdGlvbiBvZiB0aGUgcnVuIHVwIHRvIHRoZSB0aW1lIGl0IHdhcyBsYXN0IHBlcnNpc3RlZCBpbiB0aGUgZGF0YWJhc2UuIFRoaXMgcHJvY2VzcyB1c2VzIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIHJ1bidzIG1vZGVsLiBUaGVyZWZvcmUsIGlmIHRoZSBtb2RlbCBoYXMgY2hhbmdlZCBzaW5jZSB0aGUgb3JpZ2luYWwgcnVuIHdhcyBjcmVhdGVkLCB0aGUgcmV0cmlldmVkIHJ1biB3aWxsIHVzZSB0aGUgbmV3IG1vZGVsIOKAlCBhbmQgbWF5IGVuZCB1cCBoYXZpbmcgZGlmZmVyZW50IHZhbHVlcyBvciBiZWhhdmlvciBhcyBhIHJlc3VsdC4gVXNlIHdpdGggY2FyZSFcbiAqXG4gKiBUbyB1c2UgdGhlIFN0YXRlIEFQSSBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBjYWxsIGl0cyBtZXRob2RzOlxuICpcbiAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJ30pO1xuICpcbiAqIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgcHJvamVjdGAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4gKlxuICovXG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBhcGlFbmRwb2ludCA9ICdtb2RlbC9zdGF0ZSc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgfTtcblxuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcbiAgICB2YXIgcGFyc2VSdW5JZE9yRXJyb3IgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSAmJiBwYXJhbXMucnVuSWQpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbXMucnVuSWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwYXNzIGluIGEgcnVuIGlkJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGF5IGEgcnVuLiBBZnRlciB0aGlzIGNhbGwsIHRoZSBydW4sIHdpdGggaXRzIG9yaWdpbmFsIHJ1biBpZCwgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gKEl0IGNvbnRpbnVlcyB0byBiZSBwZXJzaXN0ZWQgaW50byB0aGUgRXBpY2VudGVyIGRhdGFiYXNlIGF0IHJlZ3VsYXIgaW50ZXJ2YWxzLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJywgc3RvcEJlZm9yZTogJ2NhbGN1bGF0ZVNjb3JlJ30pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBicmluZyBiYWNrIHRvIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBgcGFyYW1zLmV4Y2x1ZGVgIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZXBsYXk6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdyZXBsYXknIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ2xvbmUgYSBnaXZlbiBydW4gYW5kIHJldHVybiBhIG5ldyBydW4gaW4gdGhlIHNhbWUgc3RhdGUgYXMgdGhlIGdpdmVuIHJ1bi5cbiAgICAgICAgKlxuICAgICAgICAqIFRoZSBuZXcgcnVuIGlkIGlzIG5vdyBhdmFpbGFibGUgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIFRoZSBuZXcgcnVuIGluY2x1ZGVzIGEgY29weSBvZiBhbGwgb2YgdGhlIGRhdGEgZnJvbSB0aGUgb3JpZ2luYWwgcnVuLCBFWENFUFQ6XG4gICAgICAgICpcbiAgICAgICAgKiAqIFRoZSBgc2F2ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAuXG4gICAgICAgICogKiBUaGUgYGluaXRpYWxpemVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgbm90IGNvcGllZCBmcm9tIHRoZSBvcmlnaW5hbCBydW4gcmVjb3JkLiBJdCBkZWZhdWx0cyB0byBgZmFsc2VgIGJ1dCBtYXkgY2hhbmdlIHRvIGB0cnVlYCBhcyB0aGUgbmV3IHJ1biBpcyBhZHZhbmNlZC4gRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGhhcyBiZWVuIGEgY2FsbCB0byB0aGUgYHN0ZXBgIGZ1bmN0aW9uIChmb3IgVmVuc2ltIG1vZGVscyksIHRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGlzIHNldCB0byBgdHJ1ZWAuXG4gICAgICAgICogKiBUaGUgYGNyZWF0ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyB0aGUgZGF0ZSBhbmQgdGltZSBhdCB3aGljaCB0aGUgY2xvbmUgd2FzIGNyZWF0ZWQgKG5vdCB0aGUgdGltZSB0aGF0IHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQuKVxuICAgICAgICAqXG4gICAgICAgICogVGhlIG9yaWdpbmFsIHJ1biByZW1haW5zIG9ubHkgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLWRiKS5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5jbG9uZSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnLCBleGNsdWRlOiBbJ2ludGVyaW1DYWxjdWxhdGlvbiddIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBjbG9uZSBmcm9tIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBuZXdseSBjbG9uZWQgcnVuIGlzIGFkdmFuY2VkIG9ubHkgdXAgdG8gdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgdGhpcyBtZXRob2QuXG4gICAgICAgICogQHBhcmFtIHthcnJheX0gYHBhcmFtcy5leGNsdWRlYCAoT3B0aW9uYWwpIEFycmF5IG9mIG1ldGhvZHMgdG8gZXhjbHVkZSB3aGVuIGFkdmFuY2luZyB0aGUgbmV3bHkgY2xvbmVkIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGNsb25lOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcnVuSWQgPSBwYXJzZVJ1bklkT3JFcnJvcihwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgcmVwbGF5T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHJ1bklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgYWN0aW9uOiAnY2xvbmUnIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBlcGlWZXJzaW9uID0gcmVxdWlyZSgnLi4vYXBpLXZlcnNpb24uanNvbicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IHVybHV0aWxzIHRvIGdldCBob3N0LCBzaW5jZSBubyB3aW5kb3cgb24gbm9kZVxuXG4gICAgdmFyIEFQSV9QUk9UT0NPTCA9ICdodHRwcyc7XG4gICAgdmFyIEhPU1RfQVBJX01BUFBJTkcgPSB7XG4gICAgICAgICdmb3Jpby5jb20nOiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICdmb3Jpb2Rldi5jb20nOiAnYXBpLmVwaWNlbnRlci5mb3Jpb2Rldi5jb20nXG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNFeHBvcnRzID0ge1xuICAgICAgICBwcm90b2NvbDogQVBJX1BST1RPQ09MLFxuXG4gICAgICAgIGFwaTogJycsXG5cbiAgICAgICAgaG9zdDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICBpZiAoIWhvc3QgfHwgaG9zdC5pbmRleE9mKCdsb2NhbCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGhvc3QgPSAnZm9yaW8uY29tJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAoSE9TVF9BUElfTUFQUElOR1tob3N0XSkgPyBIT1NUX0FQSV9NQVBQSU5HW2hvc3RdIDogJ2FwaS4nICsgaG9zdDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBhcHBQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gcGF0aCAmJiBwYXRoWzFdIHx8ICcnO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFjY291bnRQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFjY250ID0gJyc7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIGFjY250ID0gcGF0aFsyXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhY2NudDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBwcm9qZWN0UGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwcmogPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIGlmIChwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnKSB7XG4gICAgICAgICAgICAgICAgcHJqID0gcGF0aFszXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBwcmo7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgdmVyc2lvblBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgdmVyc2lvbiA9IGVwaVZlcnNpb24udmVyc2lvbiA/IGVwaVZlcnNpb24udmVyc2lvbiArICcvJyA6ICcnO1xuICAgICAgICAgICAgcmV0dXJuIHZlcnNpb247XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgaXNMb2NhbGhvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICByZXR1cm4gKCFob3N0IHx8IGhvc3QuaW5kZXhPZignbG9jYWwnKSAhPT0gLTEpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGdldEFQSVBhdGg6IGZ1bmN0aW9uIChhcGkpIHtcbiAgICAgICAgICAgIHZhciBQUk9KRUNUX0FQSVMgPSBbJ3J1bicsICdkYXRhJywgJ2ZpbGUnXTtcblxuICAgICAgICAgICAgdmFyIGFwaVBhdGggPSB0aGlzLnByb3RvY29sICsgJzovLycgKyB0aGlzLmhvc3QgKyAnLycgKyB0aGlzLnZlcnNpb25QYXRoICsgYXBpICsgJy8nO1xuXG4gICAgICAgICAgICBpZiAoJC5pbkFycmF5KGFwaSwgUFJPSkVDVF9BUElTKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBhcGlQYXRoICs9IHRoaXMuYWNjb3VudFBhdGggKyAnLycgKyB0aGlzLnByb2plY3RQYXRoICArICcvJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhcGlQYXRoO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHB1YmxpY0V4cG9ydHMsIGNvbmZpZyk7XG4gICAgcmV0dXJuIHB1YmxpY0V4cG9ydHM7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4qICMjVXNlciBBUEkgQWRhcHRlclxuKlxuKiBUaGUgVXNlciBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHJldHJpZXZlIGRldGFpbHMgYWJvdXQgZW5kIHVzZXJzIGluIHlvdXIgdGVhbSAoYWNjb3VudCkuIEl0IGlzIGJhc2VkIG9uIHRoZSBxdWVyeWluZyBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbVXNlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvdXNlci8pLlxuKlxuKiBUbyB1c2UgdGhlIFVzZXIgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHMuXG4qXG4qICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nXG4qICAgICAgIH0pO1xuKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiogICAgICAgdWEuZ2V0KHsgdXNlck5hbWU6ICdqc21pdGgnIH0pO1xuKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4qXG4qIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgdG9rZW5gIGlmIHRoZXkgYXJlIG5vdCBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgY3VycmVudCBjb250ZXh0LlxuKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2Nlc3MgdG9rZW4gdG8gdXNlIHdoZW4gc2VhcmNoaW5nIGZvciBlbmQgdXNlcnMuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgcGFydGljdWxhciBlbmQgdXNlcnMgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIG5hbWUgb3IgdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4gICAgICAgICogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgZmlsdGVyYCBPYmplY3Qgd2l0aCBmaWVsZCBgdXNlck5hbWVgIGFuZCB2YWx1ZSBvZiB0aGUgdXNlcm5hbWUuIEFsdGVybmF0aXZlbHksIG9iamVjdCB3aXRoIGZpZWxkIGBpZGAgYW5kIHZhbHVlIG9mIGFuIGFycmF5IG9mIHVzZXIgaWRzLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWx0ZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciB0b1FGaWx0ZXIgPSBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgLy8gQVBJIG9ubHkgc3VwcG9ydHMgZmlsdGVyaW5nIGJ5IHVzZXJuYW1lIGZvciBub3dcbiAgICAgICAgICAgICAgICBpZiAoZmlsdGVyLnVzZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5xID0gZmlsdGVyLnVzZXJOYW1lO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgdG9JZEZpbHRlcnMgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZCA9ICQuaXNBcnJheShpZCkgPyBpZCA6IFtpZF07XG4gICAgICAgICAgICAgICAgcmV0dXJuICdpZD0nICsgaWQuam9pbignJmlkPScpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIGdldEZpbHRlcnMgPSBbXG4gICAgICAgICAgICAgICAgJ2FjY291bnQ9JyArIGdldE9wdGlvbnMuYWNjb3VudCxcbiAgICAgICAgICAgICAgICB0b0lkRmlsdGVycyhmaWx0ZXIuaWQpLFxuICAgICAgICAgICAgICAgIHF1dGlsLnRvUXVlcnlGb3JtYXQodG9RRmlsdGVyKGZpbHRlcikpXG4gICAgICAgICAgICBdLmpvaW4oJyYnKTtcblxuICAgICAgICAgICAgLy8gc3BlY2lhbCBjYXNlIGZvciBxdWVyaWVzIHdpdGggbGFyZ2UgbnVtYmVyIG9mIGlkc1xuICAgICAgICAgICAgLy8gbWFrZSBpdCBhcyBhIHBvc3Qgd2l0aCBHRVQgc2VtYW50aWNzXG4gICAgICAgICAgICB2YXIgdGhyZXNob2xkID0gMzA7XG4gICAgICAgICAgICBpZiAoZmlsdGVyLmlkICYmICQuaXNBcnJheShmaWx0ZXIuaWQpICYmIGZpbHRlci5pZC5sZW5ndGggPj0gdGhyZXNob2xkKSB7XG4gICAgICAgICAgICAgICAgZ2V0T3B0aW9ucy51cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpICsgJz9fbWV0aG9kPUdFVCc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGlkOiBmaWx0ZXIuaWQgfSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRGaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGEgc2luZ2xlIGVuZCB1c2VyIGluIHlvdXIgdGVhbSwgYmFzZWQgb24gdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRCeUlkOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcHVibGljQVBJLmdldCh7IGlkOiB1c2VySWQgfSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG5cblxuXG5cbiIsIi8qKlxuICpcbiAqICMjVmFyaWFibGVzIEFQSSBTZXJ2aWNlXG4gKlxuICogVXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSB0byByZWFkLCB3cml0ZSwgYW5kIHNlYXJjaCBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLlxuICpcbiAqICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJ1xuICogICAgICAgICAgIH1cbiAqICAgICAgfSk7XG4gKiAgICAgcm0uZ2V0UnVuKClcbiAqICAgICAgIC50aGVuKGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgdmFyIHZzID0gcm0ucnVuLnZhcmlhYmxlcygpO1xuICogICAgICAgICAgdnMuc2F2ZSh7c2FtcGxlX2ludDogNH0pO1xuICogICAgICAgIH0pO1xuICpcbiAqL1xuXG5cbiAndXNlIHN0cmljdCc7XG5cbiB2YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG4gdmFyIHJ1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9ydW4tdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcnVucyBvYmplY3QgdG8gd2hpY2ggdGhlIHZhcmlhYmxlIGZpbHRlcnMgYXBwbHkuIERlZmF1bHRzIHRvIG51bGwuXG4gICAgICAgICAqIEB0eXBlIHtydW5TZXJ2aWNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcnVuU2VydmljZTogbnVsbFxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ3ZhcmlhYmxlcy8nO1xuICAgIH07XG5cbiAgICB2YXIgYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9IHtcbiAgICAgICAgdXJsOiBnZXRVUkxcbiAgICB9O1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICBodHRwLnNwbGl0R2V0ID0gcnV0aWwuc3BsaXRHZXRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB2YWx1ZXMgZm9yIGEgdmFyaWFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMubG9hZCgnc2FtcGxlX2ludCcpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCl7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgY29udGFpbnMgdGhlIHZhbHVlIG9mIHNhbXBsZV9pbnRcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgdmFyaWFibGVgIE5hbWUgb2YgdmFyaWFibGUgdG8gbG9hZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHZhcmlhYmxlLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG91dHB1dE1vZGlmaWVyLCAkLmV4dGVuZCh7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IGdldFVSTCgpICsgdmFyaWFibGUgKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHZhcmlhYmxlcywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxdWVyeWAgb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KFsncHJpY2UnLCAnc2FsZXMnXSlcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgaXMgYW4gb2JqZWN0IHdpdGggdGhlIHZhbHVlcyBvZiB0aGUgcmVxdWVzdGVkIHZhcmlhYmxlczogdmFsLnByaWNlLCB2YWwuc2FsZXNcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoeyBpbmNsdWRlOlsncHJpY2UnLCAnc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IGBxdWVyeWAgVGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgcmVxdWVzdGVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9RdWVyeSBhbmQgb3V0cHV0TW9kaWZpZXIgYXJlIGJvdGggcXVlcnlzdHJpbmdzIGluIHRoZSB1cmw7IG9ubHkgY2FsbGluZyB0aGVtIG91dCBzZXBhcmF0ZWx5IGhlcmUgdG8gYmUgY29uc2lzdGVudCB3aXRoIHRoZSBvdGhlciBjYWxsc1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KHF1ZXJ5KSkge1xuICAgICAgICAgICAgICAgIHF1ZXJ5ID0geyBpbmNsdWRlOiBxdWVyeSB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJC5leHRlbmQocXVlcnksIG91dHB1dE1vZGlmaWVyKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KHF1ZXJ5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgdmFsdWVzIHRvIG1vZGVsIHZhcmlhYmxlcy4gT3ZlcndyaXRlcyBleGlzdGluZyB2YWx1ZXMuIE5vdGUgdGhhdCB5b3UgY2FuIG9ubHkgdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoQW4gYWx0ZXJuYXRlIHdheSB0byB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlzIHRvIGNhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwgYW5kIG1ha2Ugc3VyZSB0aGF0IHRoZSBtZXRob2QgcGVyc2lzdHMgdGhlIHZhcmlhYmxlcy4gU2VlIGBkb2AsIGBzZXJpYWxgLCBhbmQgYHBhcmFsbGVsYCBpbiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgZm9yIGNhbGxpbmcgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMuc2F2ZSgncHJpY2UnLCA0KTtcbiAgICAgICAgICogICAgICB2cy5zYXZlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgdmFyaWFibGVgIEFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgbW9kZWwgdmFyaWFibGVzIGFuZCB0aGUgdmFsdWVzIHRvIHNhdmUuIEFsdGVybmF0aXZlbHksIGEgc3RyaW5nIHdpdGggdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbGAgKE9wdGlvbmFsKSBJZiBwYXNzaW5nIGEgc3RyaW5nIGZvciBgdmFyaWFibGVgLCB1c2UgdGhpcyBhcmd1bWVudCBmb3IgdGhlIHZhbHVlIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uICh2YXJpYWJsZSwgdmFsLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW3ZhcmlhYmxlXSA9IHZhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoLmNhbGwodGhpcywgYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdCBBdmFpbGFibGUgdW50aWwgdW5kZXJseWluZyBBUEkgc3VwcG9ydHMgUFVULiBPdGhlcndpc2Ugc2F2ZSB3b3VsZCBiZSBQVVQgYW5kIG1lcmdlIHdvdWxkIGJlIFBBVENIXG4gICAgICAgIC8vICpcbiAgICAgICAgLy8gICogU2F2ZSB2YWx1ZXMgdG8gdGhlIGFwaS4gTWVyZ2VzIGFycmF5cywgYnV0IG90aGVyd2lzZSBzYW1lIGFzIHNhdmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSB2YXJpYWJsZSBPYmplY3Qgd2l0aCBhdHRyaWJ1dGVzLCBvciBzdHJpbmcga2V5XG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSB2YWwgT3B0aW9uYWwgaWYgcHJldiBwYXJhbWV0ZXIgd2FzIGEgc3RyaW5nLCBzZXQgdmFsdWUgaGVyZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAZXhhbXBsZVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSgncHJpY2UnLCA0KTtcblxuICAgICAgICAvLyBtZXJnZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgLy8gICAgIHZhciBhdHRycztcbiAgICAgICAgLy8gICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIC8vICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgIC8vICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAvLyAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAvLyAgICAgfVxuICAgICAgICAvLyAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAvLyAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICAvLyB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNXb3JsZCBBUEkgQWRhcHRlclxuICpcbiAqIEEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsIC0tIGluY2x1ZGluZyBzZXR0aW5nIHZhcmlhYmxlcywgbWFraW5nIGRlY2lzaW9ucywgYW5kIGNhbGxpbmcgb3BlcmF0aW9ucy4gRm9yIGJ1aWxkaW5nIG11bHRpcGxheWVyIHNpbXVsYXRpb25zIHlvdSB0eXBpY2FsbHkgd2FudCBtdWx0aXBsZSBlbmQgdXNlcnMgdG8gc2hhcmUgdGhlIHNhbWUgc2V0IG9mIGludGVyYWN0aW9ucywgYW5kIHdvcmsgd2l0aGluIGEgY29tbW9uIHN0YXRlLiBFcGljZW50ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUgXCJ3b3JsZHNcIiB0byBoYW5kbGUgc3VjaCBjYXNlcy4gT25seSBbdGVhbSBwcm9qZWN0c10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIGNhbiBiZSBtdWx0aXBsYXllci5cbiAqXG4gKiBUaGUgV29ybGQgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUsIGFjY2VzcywgYW5kIG1hbmlwdWxhdGUgbXVsdGlwbGF5ZXIgd29ybGRzIHdpdGhpbiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBZb3UgY2FuIHVzZSB0aGlzIHRvIGFkZCBhbmQgcmVtb3ZlIGVuZCB1c2VycyBmcm9tIHRoZSB3b3JsZCwgYW5kIHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgcmVtb3ZlIHRoZWlyIHJ1bnMuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4gKFRoZSByZWxhdGVkIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyLykgcHJvdmlkZXMgYW4gZWFzeSB3YXkgdG8gYWNjZXNzIHJ1bnMgYW5kIHdvcmxkcyBmb3IgcGFydGljdWxhciBlbmQgdXNlcnMsIHNvIGlzIHR5cGljYWxseSB1c2VkIGluIHBhZ2VzIHRoYXQgZW5kIHVzZXJzIHdpbGwgaW50ZXJhY3Qgd2l0aC4pXG4gKlxuICogQXMgd2l0aCBhbGwgdGhlIG90aGVyIFtBUEkgQWRhcHRlcnNdKC4uLy4uLyksIGFsbCBtZXRob2RzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBXb3JsZCBBUEkgU2VydmljZSBkZWZhdWx0cy5cbiAqXG4gKiBUbyB1c2UgdGhlIFdvcmxkIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSksIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKSwgYW5kIGdyb3VwICgqKkdyb3VwIE5hbWUqKikuXG4gKlxuICogICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gKiAgICAgICB3YS5jcmVhdGUoKVxuICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAqICAgICAgICAgICAgICAvLyBjYWxsIG1ldGhvZHMsIGUuZy4gd2EuYWRkVXNlcnMoKVxuICogICAgICAgICAgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG4vLyB2YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGFwaUJhc2UgPSAnbXVsdGlwbGF5ZXIvJztcbnZhciBhc3NpZ25tZW50RW5kcG9pbnQgPSBhcGlCYXNlICsgJ2Fzc2lnbic7XG52YXIgYXBpRW5kcG9pbnQgPSBhcGlCYXNlICsgJ3dvcmxkJztcbnZhciBwcm9qZWN0RW5kcG9pbnQgPSBhcGlCYXNlICsgJ3Byb2plY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkoeyBzeW5jaHJvbm91czogdHJ1ZSB9KTtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgZ3JvdXA6IHVuZGVmaW5lZCxcblxuICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIHJ1bnMgaW4gdGhpcyB3b3JsZC4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbW9kZWw6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JpdGVyaWEgYnkgd2hpY2ggdG8gZmlsdGVyIHdvcmxkLiBDdXJyZW50bHkgb25seSBzdXBwb3J0cyB3b3JsZC1pZHMgYXMgZmlsdGVycy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlbmllbmNlIGFsaWFzIGZvciBmaWx0ZXJcbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3BcbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMucHJvamVjdCA9IHVybENvbmZpZy5wcm9qZWN0UGF0aDtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBzZXRJZEZpbHRlck9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmlkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gd29ybGQgaWQgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdC4gVGhpcyBjb3VsZCBoYXBwZW4gaWYgdGhlIHVzZXIgaXMgbm90IGFzc2lnbmVkIHRvIGEgd29ybGQgYW5kIGlzIHRyeWluZyB0byB3b3JrIHdpdGggcnVucyBmcm9tIHRoYXQgd29ybGQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAoIW9wdGlvbnMubW9kZWwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gbW9kZWwgc3BlY2lmaWVkIHRvIGdldCB0aGUgY3VycmVudCBydW4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENyZWF0ZXMgYSBuZXcgV29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBVc2luZyB0aGlzIG1ldGhvZCBpcyByYXJlLiBJdCBpcyBtb3JlIGNvbW1vbiB0byBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkgd2hpbGUgeW91IGBhdXRvQXNzaWduKClgIGVuZCB1c2VycyB0byB3b3JsZHMuIChJbiB0aGlzIGNhc2UsIGNvbmZpZ3VyYXRpb24gZGF0YSBmb3IgdGhlIHdvcmxkLCBzdWNoIGFzIHRoZSByb2xlcywgYXJlIHJlYWQgZnJvbSB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9uLCBmb3IgZXhhbXBsZSBieSBgZ2V0UHJvamVjdFNldHRpbmdzKClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSh7XG4gICAgICAgICogICAgICAgICAgIHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddXG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBjcmVhdGUgdGhlIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwYCAoT3B0aW9uYWwpIFRoZSAqKkdyb3VwIE5hbWUqKiB0byBjcmVhdGUgdGhpcyB3b3JsZCB1bmRlci4gT25seSBlbmQgdXNlcnMgaW4gdGhpcyBncm91cCBhcmUgZWxpZ2libGUgdG8gam9pbiB0aGUgd29ybGQuIE9wdGlvbmFsIGhlcmU7IHJlcXVpcmVkIHdoZW4gaW5zdGFudGlhdGluZyB0aGUgc2VydmljZSAoYG5ldyBGLnNlcnZpY2UuV29ybGQoKWApLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfSk7XG4gICAgICAgICAgICB2YXIgd29ybGRBcGlQYXJhbXMgPSBbJ3Njb3BlJywgJ2ZpbGVzJywgJ3JvbGVzJywgJ29wdGlvbmFsUm9sZXMnLCAnbWluVXNlcnMnLCAnZ3JvdXAnLCAnbmFtZSddO1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHdvcmxkQXBpUGFyYW1zKTtcblxuICAgICAgICAgICAgLy8gYWNjb3VudCBhbmQgcHJvamVjdCBnbyBpbiB0aGUgYm9keSwgbm90IGluIHRoZSB1cmxcbiAgICAgICAgICAgICQuZXh0ZW5kKHBhcmFtcywgX3BpY2soc2VydmljZU9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pKTtcblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBVcGRhdGVzIGEgV29ybGQsIGZvciBleGFtcGxlIHRvIHJlcGxhY2UgdGhlIHJvbGVzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgeW91IGNvbXBsZXRlIHdvcmxkIGNvbmZpZ3VyYXRpb24gYXQgdGhlIHByb2plY3QgbGV2ZWwsIHJhdGhlciB0aGFuIGF0IHRoZSB3b3JsZCBsZXZlbC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguIEhvd2V2ZXIsIHRoaXMgbWV0aG9kIGlzIGF2YWlsYWJsZSBpZiB5b3UgbmVlZCB0byB1cGRhdGUgdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBwYXJ0aWN1bGFyIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnVwZGF0ZSh7IHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHVwZGF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMubmFtZWAgQSBzdHJpbmcgaWRlbnRpZmllciBmb3IgdGhlIGxpbmtlZCBlbmQgdXNlcnMsIGZvciBleGFtcGxlLCBcIm5hbWVcIjogXCJPdXIgVGVhbVwiLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHdoaXRlbGlzdCA9IFsncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycyddO1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHVwZGF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zIHx8IHt9LCB3aGl0ZWxpc3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChwYXJhbXMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYW4gZXhpc3Rpbmcgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBUaGlzIGZ1bmN0aW9uIG9wdGlvbmFsbHkgdGFrZXMgb25lIGFyZ3VtZW50LiBJZiB0aGUgYXJndW1lbnQgaXMgYSBzdHJpbmcsIGl0IGlzIHRoZSBpZCBvZiB0aGUgd29ybGQgdG8gZGVsZXRlLiBJZiB0aGUgYXJndW1lbnQgaXMgYW4gb2JqZWN0LCBpdCBpcyB0aGUgb3ZlcnJpZGUgZm9yIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmRlbGV0ZSgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUsIG9yIG9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAob3B0aW9ucyAmJiAodHlwZW9mIG9wdGlvbnMgPT09ICdzdHJpbmcnKSkgPyB7IGZpbHRlcjogb3B0aW9ucyB9IDoge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRlbGV0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGRlbGV0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBjdXJyZW50IGluc3RhbmNlIG9mIHRoZSBXb3JsZCBBUEkgQWRhcHRlciAoaW5jbHVkaW5nIGFsbCBzdWJzZXF1ZW50IGZ1bmN0aW9uIGNhbGxzLCB1bnRpbCB0aGUgY29uZmlndXJhdGlvbiBpcyB1cGRhdGVkIGFnYWluKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoey4uLn0pLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogJzEyMycgfSkuYWRkVXNlcih7IHVzZXJJZDogJzEyMycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgY29uZmlnYCBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gdXNlIGluIHVwZGF0aW5nIGV4aXN0aW5nIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZUNvbmZpZzogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMsIGNvbmZpZyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIExpc3RzIGFsbCB3b3JsZHMgZm9yIGEgZ2l2ZW4gYWNjb3VudCwgcHJvamVjdCwgYW5kIGdyb3VwLiBBbGwgdGhyZWUgYXJlIHJlcXVpcmVkLCBhbmQgaWYgbm90IHNwZWNpZmllZCBhcyBwYXJhbWV0ZXJzLCBhcmUgcmVhZCBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJ0ZWFtMVwiXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5saXN0KCk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJvdGhlci1ncm91cC1uYW1lXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoeyBncm91cDogJ290aGVyLWdyb3VwLW5hbWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBsaXN0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGFsbCB3b3JsZHMgdGhhdCBhbiBlbmQgdXNlciBiZWxvbmdzIHRvIGZvciBhIGdpdmVuIGFjY291bnQgKHRlYW0pLCBwcm9qZWN0LCBhbmQgZ3JvdXAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZ2V0V29ybGRzRm9yVXNlcignYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJylcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZHMgYXJlIGJlaW5nIHJldHJpZXZlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldFdvcmxkc0ZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YXIgZmlsdGVycyA9ICQuZXh0ZW5kKFxuICAgICAgICAgICAgICAgIF9waWNrKGdldE9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pLFxuICAgICAgICAgICAgICAgIHsgdXNlcklkOiB1c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGluZm9ybWF0aW9uIGZvciBhIHNwZWNpZmljIHdvcmxkLiBBbGwgZnVydGhlciBjYWxscyB0byB0aGUgd29ybGQgc2VydmljZSB3aWxsIHVzZSB0aGUgaWQgcHJvdmlkZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgd29ybGRJZGAgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBsb2FkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgd29ybGRpZCB0byBsb2FkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy8nIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQWRkcyBhbiBlbmQgdXNlciBvciBsaXN0IG9mIGVuZCB1c2VycyB0byBhIGdpdmVuIHdvcmxkLiBUaGUgZW5kIHVzZXIgbXVzdCBiZSBhIG1lbWJlciBvZiB0aGUgYGdyb3VwYCB0aGF0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlclxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoWydiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2Vycyh7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdWUCBTYWxlcycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBzZXZlcmFsIHVzZXJzXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgeyB1c2VySWQ6ICdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ1ZQIE1hcmtldGluZycgfSxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgRW5naW5lZXJpbmcnIH1cbiAgICAgICAgKiAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgICAgICAvLyBhZGQgb25lIHVzZXIgdG8gYSBzcGVjaWZpYyB3b3JsZFxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB7IGZpbHRlcjogd29ybGQuaWQgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdHxhcnJheX0gYHVzZXJzYCBVc2VyIGlkLCBhcnJheSBvZiB1c2VyIGlkcywgb2JqZWN0LCBvciBhcnJheSBvZiBvYmplY3RzIG9mIHRoZSB1c2VycyB0byBhZGQgdG8gdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJzLnJvbGVgIFRoZSBgcm9sZWAgdGhlIHVzZXIgc2hvdWxkIGhhdmUgaW4gdGhlIHdvcmxkLiBJdCBpcyB1cCB0byB0aGUgY2FsbGVyIHRvIGVuc3VyZSwgaWYgbmVlZGVkLCB0aGF0IHRoZSBgcm9sZWAgcGFzc2VkIGluIGlzIG9uZSBvZiB0aGUgYHJvbGVzYCBvciBgb3B0aW9uYWxSb2xlc2Agb2YgdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSB3b3JsZCB0byB3aGljaCB0aGUgdXNlcnMgc2hvdWxkIGJlIGFkZGVkLiBJZiBub3Qgc3BlY2lmaWVkLCB0aGUgZmlsdGVyIHBhcmFtZXRlciBvZiB0aGUgYG9wdGlvbnNgIG9iamVjdCBpcyB1c2VkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgYWRkVXNlcnM6IGZ1bmN0aW9uICh1c2Vycywgd29ybGRJZCwgb3B0aW9ucykge1xuXG4gICAgICAgICAgICBpZiAoIXVzZXJzKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhIGxpc3Qgb2YgdXNlcnMgdG8gYWRkIHRvIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBub3JtYWxpemUgdGhlIGxpc3Qgb2YgdXNlcnMgdG8gYW4gYXJyYXkgb2YgdXNlciBvYmplY3RzXG4gICAgICAgICAgICB1c2VycyA9ICQubWFwKFtdLmNvbmNhdCh1c2VycyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KHUpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1ICE9PSAnc3RyaW5nJyAmJiAhaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTb21lIG9mIHRoZSB1c2VycyBpbiB0aGUgbGlzdCBhcmUgbm90IGluIHRoZSB2YWxpZCBmb3JtYXQ6ICcgKyB1KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gaXNPYmplY3QgPyB1IDogeyB1c2VySWQ6IHUgfTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBjaGVjayBpZiBvcHRpb25zIHdlcmUgcGFzc2VkIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHdvcmxkSWQpICYmICFvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHdvcmxkSWQ7XG4gICAgICAgICAgICAgICAgd29ybGRJZCA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICAvLyB3ZSBtdXN0IGhhdmUgb3B0aW9ucyBieSBub3dcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygd29ybGRJZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvdXNlcnMnIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QodXNlcnMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIHJvbGUgb2YgYW4gZW5kIHVzZXIgaW4gYSBnaXZlbiB3b3JsZC4gKFlvdSBjYW4gb25seSB1cGRhdGUgb25lIGVuZCB1c2VyIGF0IGEgdGltZS4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuY3JlYXRlKCkudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgIHdhLnVwZGF0ZVVzZXIoeyB1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCByb2xlOiAnbGVhZGVyJyB9KTtcbiAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHVzZXJgIFVzZXIgb2JqZWN0IHdpdGggYHVzZXJJZGAgYW5kIHRoZSBuZXcgYHJvbGVgLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICghdXNlciB8fCAhdXNlci51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHBhc3MgYSB1c2VySWQgdG8gdXBkYXRlIGZyb20gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcGF0Y2hPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goX3BpY2sodXNlciwgJ3JvbGUnKSwgcGF0Y2hPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZW1vdmVzIGFuIGVuZCB1c2VyIGZyb20gYSBnaXZlbiB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5yZW1vdmVVc2VyKCdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoeyB1c2VySWQ6ICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdHxzdHJpbmd9IGB1c2VyYCBUaGUgYHVzZXJJZGAgb2YgdGhlIHVzZXIgdG8gcmVtb3ZlIGZyb20gdGhlIHdvcmxkLCBvciBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgYHVzZXJJZGAgZmllbGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdXNlciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICB1c2VyID0geyB1c2VySWQ6IHVzZXIgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHJ1biBpZCBvZiBjdXJyZW50IHJ1biBmb3IgdGhlIGdpdmVuIHdvcmxkLiBJZiB0aGUgd29ybGQgZG9lcyBub3QgaGF2ZSBhIHJ1biwgY3JlYXRlcyBhIG5ldyBvbmUgYW5kIHJldHVybnMgdGhlIHJ1biBpZC5cbiAgICAgICAgKlxuICAgICAgICAqIFJlbWVtYmVyIHRoYXQgYSBbcnVuXSguLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwuIEluIHRoZSBjYXNlIG9mIG11bHRpcGxheWVyIHByb2plY3RzLCB0aGUgcnVuIGlzIHNoYXJlZCBieSBhbGwgZW5kIHVzZXJzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRDdXJyZW50UnVuSWQoeyBtb2RlbDogJ21vZGVsLnB5JyB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRSdW5JZDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3J1bicgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoX3BpY2soZ2V0T3B0aW9ucywgJ21vZGVsJyksIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBmb3IgdGhlIGdpdmVuIGVuZCB1c2VyIGluIHRoZSBnaXZlbiBncm91cC4gQnJpbmdzIHRoaXMgbW9zdCByZWNlbnQgd29ybGQgaW50byBtZW1vcnkgaWYgbmVlZGVkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIHVzZSBkYXRhIGZyb20gd29ybGRcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSBjdXJyZW50IChtb3N0IHJlY2VudCkgd29ybGQgaXMgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cC4gSWYgbm90IHByb3ZpZGVkLCBkZWZhdWx0cyB0byB0aGUgZ3JvdXAgdXNlZCB0byBjcmVhdGUgdGhlIHNlcnZpY2UuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRXb3JsZEZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkc0ZvclVzZXIodXNlcklkLCB7IGdyb3VwOiBncm91cE5hbWUgfSlcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGFzc3VtZSB0aGUgbW9zdCByZWNlbnQgd29ybGQgYXMgdGhlICdhY3RpdmUnIHdvcmxkXG4gICAgICAgICAgICAgICAgICAgIHdvcmxkcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7IHJldHVybiBuZXcgRGF0ZShiLmxhc3RNb2RpZmllZCkgLSBuZXcgRGF0ZShhLmxhc3RNb2RpZmllZCk7IH0pO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VycmVudFdvcmxkID0gd29ybGRzWzBdO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50V29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9ICBjdXJyZW50V29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShjdXJyZW50V29ybGQsIG1lKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIHRoZSBjdXJyZW50IHJ1biBmcm9tIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIChOb3RlIHRoYXQgdGhlIHdvcmxkIGlkIHJlbWFpbnMgcGFydCBvZiB0aGUgcnVuIHJlY29yZCwgaW5kaWNhdGluZyB0aGF0IHRoZSBydW4gd2FzIGZvcm1lcmx5IGFuIGFjdGl2ZSBydW4gZm9yIHRoZSB3b3JsZC4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmRlbGV0ZVJ1bignc2FtcGxlLXdvcmxkLWlkJyk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSBgd29ybGRJZGAgb2YgdGhlIHdvcmxkIGZyb20gd2hpY2ggdGhlIGN1cnJlbnQgcnVuIGlzIGJlaW5nIGRlbGV0ZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGVSdW46IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBydW4gZm9yIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgd2EubmV3UnVuRm9yV29ybGQod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgd29ybGRJZCBpbiB3aGljaCB3ZSBjcmVhdGUgdGhlIG5ldyBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIG5ld1J1bkZvcldvcmxkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGN1cnJlbnRSdW5PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IGZpbHRlcjogd29ybGRJZCB8fCBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IoY3VycmVudFJ1bk9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kZWxldGVSdW4od29ybGRJZCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5nZXRDdXJyZW50UnVuSWQoY3VycmVudFJ1bk9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEFzc2lnbnMgZW5kIHVzZXJzIHRvIHdvcmxkcywgY3JlYXRpbmcgbmV3IHdvcmxkcyBhcyBhcHByb3ByaWF0ZSwgYXV0b21hdGljYWxseS4gQXNzaWducyBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cCwgYW5kIGNyZWF0ZXMgbmV3IHdvcmxkcyBhcyBuZWVkZWQgYmFzZWQgb24gdGhlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbiAocm9sZXMsIG9wdGlvbmFsIHJvbGVzLCBhbmQgbWluaW11bSBlbmQgdXNlcnMgcGVyIHdvcmxkKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5hdXRvQXNzaWduKCk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBhdXRvQXNzaWduOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhc3NpZ25tZW50RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBwYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3B0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgcHJvamVjdDogb3B0LnByb2plY3QsXG4gICAgICAgICAgICAgICAgZ3JvdXA6IG9wdC5ncm91cFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKG9wdC5tYXhVc2Vycykge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5tYXhVc2VycyA9IG9wdC5tYXhVc2VycztcbiAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgb3B0KTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBwcm9qZWN0J3Mgd29ybGQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgZXZlcnkgaW50ZXJhY3Rpb24gd2l0aCB5b3VyIHByb2plY3QgdXNlcyB0aGUgc2FtZSBjb25maWd1cmF0aW9uIG9mIGVhY2ggd29ybGQuIEZvciBleGFtcGxlLCBlYWNoIHdvcmxkIGluIHlvdXIgcHJvamVjdCBwcm9iYWJseSBoYXMgdGhlIHNhbWUgcm9sZXMgZm9yIGVuZCB1c2Vycy4gQW5kIHlvdXIgcHJvamVjdCBpcyBwcm9iYWJseSBlaXRoZXIgY29uZmlndXJlZCBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgc2hhcmUgdGhlIHNhbWUgd29ybGQgKGFuZCBydW4pLCBvciBzbWFsbGVyIHNldHMgb2YgZW5kIHVzZXJzIHNoYXJlIHdvcmxkcyDigJQgYnV0IG5vdCBib3RoLlxuICAgICAgICAqXG4gICAgICAgICogKFRoZSBbTXVsdGlwbGF5ZXIgUHJvamVjdCBSRVNUIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL211bHRpcGxheWVyX3Byb2plY3QvKSBhbGxvd3MgeW91IHRvIHNldCB0aGVzZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb25zLiBUaGUgV29ybGQgQWRhcHRlciBzaW1wbHkgcmV0cmlldmVzIHRoZW0sIGZvciBleGFtcGxlIHNvIHRoZXkgY2FuIGJlIHVzZWQgaW4gYXV0by1hc3NpZ25tZW50IG9mIGVuZCB1c2VycyB0byB3b3JsZHMuKVxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmdldFByb2plY3RTZXR0aW5ncygpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHNldHRpbmdzKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5yb2xlcyk7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5vcHRpb25hbFJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0UHJvamVjdFNldHRpbmdzOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChwcm9qZWN0RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIG9wdC51cmwgKz0gW29wdC5hY2NvdW50LCBvcHQucHJvamVjdF0uam9pbignLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQobnVsbCwgb3B0KTtcbiAgICAgICAgfVxuXG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29va2llIFN0b3JhZ2UgU2VydmljZVxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgIHZhciBwZW9wbGUgPSByZXF1aXJlKCdjb29raWUtc3RvcmUnKSh7IHJvb3Q6ICdwZW9wbGUnIH0pO1xuICAgICAgICBwZW9wbGVcbiAgICAgICAgICAgIC5zYXZlKHtsYXN0TmFtZTogJ3NtaXRoJyB9KVxuXG4gKi9cblxuXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5hbWUgb2YgY29sbGVjdGlvblxuICAgICAgICAgKiBAdHlwZSB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHJvb3Q6ICcvJyxcblxuICAgICAgICBkb21haW46ICcuZm9yaW8uY29tJ1xuICAgIH07XG4gICAgdGhpcy5zZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIC8vICogVEJEXG4gICAgICAgIC8vICAqIFF1ZXJ5IGNvbGxlY3Rpb247IHVzZXMgTW9uZ29EQiBzeW50YXhcbiAgICAgICAgLy8gICogQHNlZSAgPFRCRDogRGF0YSBBUEkgVVJMPlxuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IHFzIFF1ZXJ5IEZpbHRlclxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IGxpbWl0ZXJzIEBzZWUgPFRCRDogdXJsIGZvciBsaW1pdHMsIHBhZ2luZyBldGM+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBleGFtcGxlXG4gICAgICAgIC8vICAqICAgICBjcy5xdWVyeShcbiAgICAgICAgLy8gICogICAgICB7IG5hbWU6ICdKb2huJywgY2xhc3NOYW1lOiAnQ1NDMTAxJyB9LFxuICAgICAgICAvLyAgKiAgICAgIHtsaW1pdDogMTB9XG4gICAgICAgIC8vICAqICAgICApXG5cbiAgICAgICAgLy8gcXVlcnk6IGZ1bmN0aW9uIChxcywgbGltaXRlcnMpIHtcblxuICAgICAgICAvLyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGNvb2tpZSB2YWx1ZVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5ICAgSWYgZ2l2ZW4gYSBrZXkgc2F2ZSB2YWx1ZXMgdW5kZXIgaXQsIGlmIGdpdmVuIGFuIG9iamVjdCBkaXJlY3RseSwgc2F2ZSB0byB0b3AtbGV2ZWwgYXBpXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gdmFsdWUgKE9wdGlvbmFsKVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIHNlcnZpY2Ugb3B0aW9uc1xuICAgICAgICAgKlxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgc2F2ZWQgdmFsdWVcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnNldCgncGVyc29uJywgeyBmaXJzdE5hbWU6ICdqb2huJywgbGFzdE5hbWU6ICdzbWl0aCcgfSk7XG4gICAgICAgICAqICAgICBjcy5zZXQoeyBuYW1lOidzbWl0aCcsIGFnZTonMzInIH0pO1xuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHNldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5zZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSBzZXRPcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2V0T3B0aW9ucy5yb290O1xuXG4gICAgICAgICAgICBkb2N1bWVudC5jb29raWUgPSBlbmNvZGVVUklDb21wb25lbnQoa2V5KSArICc9JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuY29kZVVSSUNvbXBvbmVudCh2YWx1ZSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG5cbiAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9hZCBjb29raWUgdmFsdWVcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSAgIElmIGdpdmVuIGEga2V5IHNhdmUgdmFsdWVzIHVuZGVyIGl0LCBpZiBnaXZlbiBhbiBvYmplY3QgZGlyZWN0bHksIHNhdmUgdG8gdG9wLWxldmVsIGFwaVxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgdmFsdWUgc3RvcmVkXG4gICAgICAgICAqXG4gICAgICAgICAqIEBleGFtcGxlXG4gICAgICAgICAqICAgICBjcy5nZXQoJ3BlcnNvbicpO1xuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgY29va2llUmVnID0gbmV3IFJlZ0V4cCgnKD86KD86XnwuKjspXFxcXHMqJyArIGVuY29kZVVSSUNvbXBvbmVudChrZXkpLnJlcGxhY2UoL1tcXC1cXC5cXCtcXCpdL2csICdcXFxcJCYnKSArICdcXFxccypcXFxcPVxcXFxzKihbXjtdKikuKiQpfF4uKiQnKTtcbiAgICAgICAgICAgIHZhciB2YWwgPSBkb2N1bWVudC5jb29raWUucmVwbGFjZShjb29raWVSZWcsICckMScpO1xuICAgICAgICAgICAgdmFsID0gZGVjb2RlVVJJQ29tcG9uZW50KHZhbCkgfHwgbnVsbDtcbiAgICAgICAgICAgIHJldHVybiB2YWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMga2V5IGZyb20gY29sbGVjdGlvblxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGtleSBrZXkgdG8gcmVtb3ZlXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9IGtleSBUaGUga2V5IHJlbW92ZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnJlbW92ZSgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciByZW1PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMuc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9tYWluID0gcmVtT3B0aW9ucy5kb21haW47XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHJlbU9wdGlvbnMucm9vdDtcblxuICAgICAgICAgICAgZG9jdW1lbnQuY29va2llID0gZW5jb2RlVVJJQ29tcG9uZW50KGtleSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICc9OyBleHBpcmVzPVRodSwgMDEgSmFuIDE5NzAgMDA6MDA6MDAgR01UJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGRvbWFpbiA/ICc7IGRvbWFpbj0nICsgZG9tYWluIDogJycpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG4gICAgICAgICAgICByZXR1cm4ga2V5O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIGNvbGxlY3Rpb24gYmVpbmcgcmVmZXJlbmNlZFxuICAgICAgICAgKiBAcmV0dXJuIHsgYXJyYXl9IGtleXMgQWxsIHRoZSBrZXlzIHJlbW92ZWRcbiAgICAgICAgICovXG4gICAgICAgIGRlc3Ryb3k6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhS2V5cyA9IGRvY3VtZW50LmNvb2tpZS5yZXBsYWNlKC8oKD86XnxcXHMqOylbXlxcPV0rKSg/PTt8JCl8Xlxccyp8XFxzKig/OlxcPVteO10qKT8oPzpcXDF8JCkvZywgJycpLnNwbGl0KC9cXHMqKD86XFw9W147XSopPztcXHMqLyk7XG4gICAgICAgICAgICBmb3IgKHZhciBuSWR4ID0gMDsgbklkeCA8IGFLZXlzLmxlbmd0aDsgbklkeCsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvb2tpZUtleSA9IGRlY29kZVVSSUNvbXBvbmVudChhS2V5c1tuSWR4XSk7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmUoY29va2llS2V5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhS2V5cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICAgIERlY2lkZXMgdHlwZSBvZiBzdG9yZSB0byBwcm92aWRlXG4qL1xuXG4ndXNlIHN0cmljdCc7XG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHN0b3JlID0gKGlzTm9kZSkgPyByZXF1aXJlKCcuL3Nlc3Npb24tc3RvcmUnKSA6IHJlcXVpcmUoJy4vY29va2llLXN0b3JlJyk7XG52YXIgc3RvcmUgPSByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHN0b3JlO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgcXV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgIGhlYWRlcnM6IHt9LFxuICAgICAgICBzdGF0dXNDb2RlOiB7XG4gICAgICAgICAgICA0MDQ6ICQubm9vcFxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPTkxZIGZvciBzdHJpbmdzIGluIHRoZSB1cmwuIEFsbCBHRVQgJiBERUxFVEUgcGFyYW1zIGFyZSBydW4gdGhyb3VnaCB0aGlzXG4gICAgICAgICAqIEB0eXBlIHtbdHlwZV0gfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFyYW1ldGVyUGFyc2VyOiBxdXRpbHMudG9RdWVyeUZvcm1hdCxcblxuICAgICAgICAvLyBUbyBhbGxvdyBlcGljZW50ZXIudG9rZW4gYW5kIG90aGVyIHNlc3Npb24gY29va2llcyB0byBiZSBwYXNzZWRcbiAgICAgICAgLy8gd2l0aCB0aGUgcmVxdWVzdHNcbiAgICAgICAgeGhyRmllbGRzOiB7XG4gICAgICAgICAgICB3aXRoQ3JlZGVudGlhbHM6IHRydWVcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciByZXN1bHQgPSBmdW5jdGlvbiAoZCkge1xuICAgICAgICByZXR1cm4gKCQuaXNGdW5jdGlvbihkKSkgPyBkKCkgOiBkO1xuICAgIH07XG5cbiAgICB2YXIgY29ubmVjdCA9IGZ1bmN0aW9uIChtZXRob2QsIHBhcmFtcywgY29ubmVjdE9wdGlvbnMpIHtcbiAgICAgICAgcGFyYW1zID0gcmVzdWx0KHBhcmFtcyk7XG4gICAgICAgIHBhcmFtcyA9ICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSB8fCAkLmlzQXJyYXkocGFyYW1zKSkgPyBKU09OLnN0cmluZ2lmeShwYXJhbXMpIDogcGFyYW1zO1xuXG4gICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRyYW5zcG9ydE9wdGlvbnMsIGNvbm5lY3RPcHRpb25zLCB7XG4gICAgICAgICAgICB0eXBlOiBtZXRob2QsXG4gICAgICAgICAgICBkYXRhOiBwYXJhbXNcbiAgICAgICAgfSk7XG4gICAgICAgIHZhciBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUyA9IFsnZGF0YScsICd1cmwnXTtcbiAgICAgICAgJC5lYWNoKG9wdGlvbnMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAoJC5pc0Z1bmN0aW9uKHZhbHVlKSAmJiAkLmluQXJyYXkoa2V5LCBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9uc1trZXldID0gdmFsdWUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKG9wdGlvbnMubG9nTGV2ZWwgJiYgb3B0aW9ucy5sb2dMZXZlbCA9PT0gJ0RFQlVHJykge1xuICAgICAgICAgICAgY29uc29sZS5sb2cob3B0aW9ucy51cmwpO1xuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3NGbiA9IG9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UsIGFqYXhTdGF0dXMsIGFqYXhSZXEpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgb2xkU3VjY2Vzc0ZuLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGJlZm9yZVNlbmQgPSBvcHRpb25zLmJlZm9yZVNlbmQ7XG4gICAgICAgIG9wdGlvbnMuYmVmb3JlU2VuZCA9IGZ1bmN0aW9uICh4aHIsIHNldHRpbmdzKSB7XG4gICAgICAgICAgICB4aHIucmVxdWVzdFVybCA9IChjb25uZWN0T3B0aW9ucyB8fCB7fSkudXJsO1xuICAgICAgICAgICAgaWYgKGJlZm9yZVNlbmQpIHtcbiAgICAgICAgICAgICAgICBiZWZvcmVTZW5kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuICQuYWpheChvcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgZ2V0OmZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdHRVQnLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuICAgICAgICBzcGxpdEdldDogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIH0sXG4gICAgICAgIHBvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncG9zdCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgcGF0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncGF0Y2gnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHB1dDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwdXQnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKHBhcmFtcywgYWpheE9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vREVMRVRFIGRvZXNuJ3Qgc3VwcG9ydCBib2R5IHBhcmFtcywgYnV0IGpRdWVyeSB0aGlua3MgaXQgZG9lcy5cbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRyYW5zcG9ydE9wdGlvbnMsIGFqYXhPcHRpb25zKTtcbiAgICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1ldGVyUGFyc2VyKHJlc3VsdChwYXJhbXMpKTtcbiAgICAgICAgICAgIGlmICgkLnRyaW0ocGFyYW1zKSkge1xuICAgICAgICAgICAgICAgIHZhciBkZWxpbWl0ZXIgPSAocmVzdWx0KG9wdGlvbnMudXJsKS5pbmRleE9mKCc/JykgPT09IC0xKSA/ICc/JyA6ICcmJztcbiAgICAgICAgICAgICAgICBvcHRpb25zLnVybCA9IHJlc3VsdChvcHRpb25zLnVybCkgKyBkZWxpbWl0ZXIgKyBwYXJhbXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdERUxFVEUnLCBudWxsLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgaGVhZDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydoZWFkJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBvcHRpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ29wdGlvbnMnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHRyYW5zcG9ydCA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9ub2RlLWh0dHAtdHJhbnNwb3J0JykgOiByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbnZhciB0cmFuc3BvcnQgPSByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbm1vZHVsZS5leHBvcnRzID0gdHJhbnNwb3J0O1xuIiwiLyoqXG4vKiBJbmhlcml0IGZyb20gYSBjbGFzcyAodXNpbmcgcHJvdG90eXBlIGJvcnJvd2luZylcbiovXG4ndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIGluaGVyaXQoQywgUCkge1xuICAgIHZhciBGID0gZnVuY3Rpb24gKCkge307XG4gICAgRi5wcm90b3R5cGUgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZSA9IG5ldyBGKCk7XG4gICAgQy5fX3N1cGVyID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDO1xufVxuXG4vKipcbiogU2hhbGxvdyBjb3B5IG9mIGFuIG9iamVjdFxuKi9cbnZhciBleHRlbmQgPSBmdW5jdGlvbiAoZGVzdCAvKiwgdmFyX2FyZ3MqLykge1xuICAgIHZhciBvYmogPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHZhciBjdXJyZW50O1xuICAgIGZvciAodmFyIGogPSAwOyBqPG9iai5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAoIShjdXJyZW50ID0gb2JqW2pdKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkbyBub3Qgd3JhcCBpbm5lciBpbiBkZXN0Lmhhc093blByb3BlcnR5IG9yIGJhZCB0aGluZ3Mgd2lsbCBoYXBwZW5cbiAgICAgICAgLypqc2hpbnQgLVcwODkgKi9cbiAgICAgICAgZm9yICh2YXIga2V5IGluIGN1cnJlbnQpIHtcbiAgICAgICAgICAgIGRlc3Rba2V5XSA9IGN1cnJlbnRba2V5XTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkZXN0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYmFzZSwgcHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgdmFyIHBhcmVudCA9IGJhc2U7XG4gICAgdmFyIGNoaWxkO1xuXG4gICAgY2hpbGQgPSBwcm9wcyAmJiBwcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSA/IHByb3BzLmNvbnN0cnVjdG9yIDogZnVuY3Rpb24gKCkgeyByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IH07XG5cbiAgICAvLyBhZGQgc3RhdGljIHByb3BlcnRpZXMgdG8gdGhlIGNoaWxkIGNvbnN0cnVjdG9yIGZ1bmN0aW9uXG4gICAgZXh0ZW5kKGNoaWxkLCBwYXJlbnQsIHN0YXRpY1Byb3BzKTtcblxuICAgIC8vIGFzc29jaWF0ZSBwcm90b3R5cGUgY2hhaW5cbiAgICBpbmhlcml0KGNoaWxkLCBwYXJlbnQpO1xuXG4gICAgLy8gYWRkIGluc3RhbmNlIHByb3BlcnRpZXNcbiAgICBpZiAocHJvcHMpIHtcbiAgICAgICAgZXh0ZW5kKGNoaWxkLnByb3RvdHlwZSwgcHJvcHMpO1xuICAgIH1cblxuICAgIC8vIGRvbmVcbiAgICByZXR1cm4gY2hpbGQ7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLypqc2hpbnQgbG9vcGZ1bmM6ZmFsc2UgKi9cblxuZnVuY3Rpb24gX3codmFsKSB7XG4gICAgaWYgKHZhbCAmJiB2YWwudGhlbikge1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgIH1cbiAgICB2YXIgcCA9ICQuRGVmZXJyZWQoKTtcbiAgICBwLnJlc29sdmUodmFsKTtcblxuICAgIHJldHVybiBwLnByb21pc2UoKTtcbn1cblxuZnVuY3Rpb24gc2VxKCkge1xuICAgIHZhciBsaXN0ID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmFwcGx5KGFyZ3VtZW50cyk7XG5cbiAgICBmdW5jdGlvbiBuZXh0KHApIHtcbiAgICAgICAgdmFyIGN1ciA9IGxpc3Quc3BsaWNlKDAsMSlbMF07XG5cbiAgICAgICAgaWYgKCFjdXIpIHtcbiAgICAgICAgICAgIHJldHVybiBwO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF93KGN1cihwKSkudGhlbihuZXh0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gKHNlZWQpIHtcbiAgICAgICAgcmV0dXJuIG5leHQoc2VlZCkuZmFpbChzZXEuZmFpbCk7XG4gICAgfTtcbn1cblxuZnVuY3Rpb24gTWFrZVNlcShvYmopIHtcbiAgICB2YXIgcmVzID0ge1xuICAgICAgICBfX2NhbGxzOiBbXSxcblxuICAgICAgICBvcmlnaW5hbDogb2JqLFxuXG4gICAgICAgIHRoZW46IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goZm4pO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIC8vIGNsZWFuIHVwXG4gICAgICAgICAgICB0aGlzLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIF90aGlzLl9fY2FsbHMubGVuZ3RoID0gMDtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBzZXEuYXBwbHkobnVsbCwgdGhpcy5fX2NhbGxzKSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGZhaWw6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgc2VxLmZhaWwgPSBmbjtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBmdW5jTWFrZXIgPSBmdW5jdGlvbiAocCwgb2JqKSB7XG4gICAgICAgIHZhciBmbiA9IG9ialtwXS5iaW5kKG9iaik7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goRnVuY3Rpb24uYmluZC5hcHBseShmbiwgW251bGxdLmNvbmNhdChhcmdzKSkpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH07XG4gICAgfTtcblxuICAgIGZvciAodmFyIHByb3AgaW4gb2JqKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygb2JqW3Byb3BdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXNbcHJvcF0gPSBmdW5jTWFrZXIocHJvcCwgb2JqKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlc1twcm9wXSA9IG9ialtwcm9wXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gTWFrZVNlcTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgX3BpY2s6IGZ1bmN0aW9uIChvYmosIHByb3BzKSB7XG4gICAgICAgIHZhciByZXMgPSB7fTtcbiAgICAgICAgZm9yICh2YXIgcCBpbiBvYmopIHtcbiAgICAgICAgICAgIGlmIChwcm9wcy5pbmRleE9mKHApICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIHJlc1twXSA9IG9ialtwXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxufTtcbiIsIi8qKlxuICogVXRpbGl0aWVzIGZvciB3b3JraW5nIHdpdGggcXVlcnkgc3RyaW5nc1xuKi9cbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSAoZnVuY3Rpb24gKCkge1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHRvIG1hdHJpeCBmb3JtYXRcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBxcyBPYmplY3QgdG8gY29udmVydCB0byBxdWVyeSBzdHJpbmdcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ30gICAgTWF0cml4LWZvcm1hdCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuICAgICAgICB0b01hdHJpeEZvcm1hdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCB8fCBxcyA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJzsnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgdmFyIE9QRVJBVE9SUyA9IFsnPCcsICc+JywgJyEnXTtcbiAgICAgICAgICAgICQuZWFjaChxcywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnc3RyaW5nJyB8fCAkLmluQXJyYXkoJC50cmltKHZhbHVlKS5jaGFyQXQoMCksIE9QRVJBVE9SUykgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gJz0nICsgdmFsdWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciBtdHJ4ID0gJzsnICsgcmV0dXJuQXJyYXkuam9pbignOycpO1xuICAgICAgICAgICAgcmV0dXJuIG10cng7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHN0cmluZ3MvYXJyYXlzL29iamVjdHMgdG8gdHlwZSAnYT1iJmI9YydcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b1F1ZXJ5Rm9ybWF0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgJC5lYWNoKHFzLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmICgkLmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUuam9pbignLCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICAvL01vc3RseSBmb3IgZGF0YSBhcGlcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBKU09OLnN0cmluZ2lmeSh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgJz0nICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciByZXN1bHQgPSByZXR1cm5BcnJheS5qb2luKCcmJyk7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyBzdHJpbmdzIG9mIHR5cGUgJ2E9YiZiPWMnIHRvIHsgYTpiLCBiOmN9XG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHFzXG4gICAgICAgICAqIEByZXR1cm4ge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHFzVG9PYmplY3Q6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQgfHwgcXMgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcXNBcnJheSA9IHFzLnNwbGl0KCcmJyk7XG4gICAgICAgICAgICB2YXIgcmV0dXJuT2JqID0ge307XG4gICAgICAgICAgICAkLmVhY2gocXNBcnJheSwgZnVuY3Rpb24gKGluZGV4LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBxS2V5ID0gdmFsdWUuc3BsaXQoJz0nKVswXTtcbiAgICAgICAgICAgICAgICB2YXIgcVZhbCA9IHZhbHVlLnNwbGl0KCc9JylbMV07XG5cbiAgICAgICAgICAgICAgICBpZiAocVZhbC5pbmRleE9mKCcsJykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHFWYWwgPSBxVmFsLnNwbGl0KCcsJyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuT2JqW3FLZXldID0gcVZhbDtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuT2JqO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOb3JtYWxpemVzIGFuZCBtZXJnZXMgc3RyaW5ncyBvZiB0eXBlICdhPWInLCB7IGI6Y30gdG8geyBhOmIsIGI6Y31cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzMVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXMyXG4gICAgICAgICAqIEByZXR1cm4ge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIG1lcmdlUVM6IGZ1bmN0aW9uIChxczEsIHFzMikge1xuICAgICAgICAgICAgdmFyIG9iajEgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMSkpO1xuICAgICAgICAgICAgdmFyIG9iajIgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMikpO1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHt9LCBvYmoxLCBvYmoyKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhZGRUcmFpbGluZ1NsYXNoOiBmdW5jdGlvbiAodXJsKSB7XG4gICAgICAgICAgICBpZiAoIXVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAodXJsLmNoYXJBdCh1cmwubGVuZ3RoIC0gMSkgPT09ICcvJykgPyB1cmwgOiAodXJsICsgJy8nKTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuXG5cblxuIiwiLyoqXG4gKiBVdGlsaXRpZXMgZm9yIHdvcmtpbmcgd2l0aCB0aGUgcnVuIHNlcnZpY2VcbiovXG4ndXNlIHN0cmljdCc7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuL3F1ZXJ5LXV0aWwnKTtcbnZhciBNQVhfVVJMX0xFTkdUSCA9IDIwNDg7XG5cbm1vZHVsZS5leHBvcnRzID0gKGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICAvKipcbiAgICAgICAgICogcmV0dXJucyBvcGVyYXRpb25zIG9mIHRoZSBmb3JtIGBbW29wMSxvcDJdLCBbYXJnMSwgYXJnMl1dYFxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R8QXJyYXl8U3RyaW5nfSBgb3BlcmF0aW9uc2Agb3BlcmF0aW9ucyB0byBwZXJmb3JtXG4gICAgICAgICAqIEBwYXJhbSAge0FycmF5fSBgYXJnc2AgYXJndW1lbnRzIGZvciBvcGVyYXRpb25cbiAgICAgICAgICogQHJldHVybiB7U3RyaW5nfSAgICBNYXRyaXgtZm9ybWF0IHF1ZXJ5IHBhcmFtZXRlcnNcbiAgICAgICAgICovXG4gICAgICAgIG5vcm1hbGl6ZU9wZXJhdGlvbnM6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBhcmdzKSB7XG4gICAgICAgICAgICBpZiAoIWFyZ3MpIHtcbiAgICAgICAgICAgICAgICBhcmdzID0gW107XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgcmV0dXJuTGlzdCA9IHtcbiAgICAgICAgICAgICAgICBvcHM6IFtdLFxuICAgICAgICAgICAgICAgIGFyZ3M6IFtdXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX2NvbmNhdCA9IGZ1bmN0aW9uIChhcnIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKGFyciAhPT0gbnVsbCAmJiBhcnIgIT09IHVuZGVmaW5lZCkgPyBbXS5jb25jYXQoYXJyKSA6IFtdO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgLy97IGFkZDogWzEsMl0sIHN1YnRyYWN0OiBbMiw0XSB9XG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZVBsYWluT2JqZWN0cyA9IGZ1bmN0aW9uIChvcGVyYXRpb25zLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICQuZWFjaChvcGVyYXRpb25zLCBmdW5jdGlvbiAob3BuLCBhcmcpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcG4pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KGFyZykpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIC8veyBuYW1lOiAnYWRkJywgcGFyYW1zOiBbMV0gfVxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVTdHJ1Y3R1cmVkT2JqZWN0cyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcGVyYXRpb24ubmFtZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChvcGVyYXRpb24ucGFyYW1zKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZU9iamVjdCA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKChvcGVyYXRpb24ubmFtZSkgPyBfbm9ybWFsaXplU3RydWN0dXJlZE9iamVjdHMgOiBfbm9ybWFsaXplUGxhaW5PYmplY3RzKShvcGVyYXRpb24sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVMaXRlcmFscyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIGFyZ3MsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcGVyYXRpb24pO1xuICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQoYXJncykpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZUFycmF5cyA9IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBhcmcsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJC5lYWNoKG9wZXJhdGlvbnMsIGZ1bmN0aW9uIChpbmRleCwgb3BuKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qob3BuKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgX25vcm1hbGl6ZU9iamVjdChvcG4sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgX25vcm1hbGl6ZUxpdGVyYWxzKG9wbiwgYXJnc1tpbmRleF0sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KG9wZXJhdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZU9iamVjdChvcGVyYXRpb25zLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoJC5pc0FycmF5KG9wZXJhdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZUFycmF5cyhvcGVyYXRpb25zLCBhcmdzLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZUxpdGVyYWxzKG9wZXJhdGlvbnMsIGFyZ3MsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgfSxcblxuICAgICAgICBzcGxpdEdldEZhY3Rvcnk6IGZ1bmN0aW9uIChodHRwT3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICB2YXIgaHR0cCA9IHRoaXM7XG4gICAgICAgICAgICAgICAgdmFyIGdldFZhbHVlID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhbHVlID0gb3B0aW9uc1tuYW1lXSB8fCBodHRwT3B0aW9uc1tuYW1lXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciBnZXRGaW5hbFVybCA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybCA9IGdldFZhbHVlKCd1cmwnLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRhdGEgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZXJlIGlzIGVhc3kgKG9yIGtub3duKSB3YXkgdG8gZ2V0IHRoZSBmaW5hbCBVUkwganF1ZXJ5IGlzIGdvaW5nIHRvIHNlbmQgc29cbiAgICAgICAgICAgICAgICAgICAgLy8gd2UncmUgcmVwbGljYXRpbmcgaXQuIFRoZSBwcm9jZXNzIG1pZ2h0IGNoYW5nZSBhdCBzb21lIHBvaW50IGJ1dCBpdCBwcm9iYWJseSB3aWxsIG5vdC5cbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gUmVtb3ZlIGhhc2hcbiAgICAgICAgICAgICAgICAgICAgdXJsID0gdXJsLnJlcGxhY2UoLyMuKiQvLCAnJyk7XG4gICAgICAgICAgICAgICAgICAgIC8vIDEuIEFwcGVuZCBxdWVyeSBzdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXJ5UGFyYW1zID0gcXV0aWwudG9RdWVyeUZvcm1hdChkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXN0aW9uSWR4ID0gdXJsLmluZGV4T2YoJz8nKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHF1ZXJ5UGFyYW1zICYmIHF1ZXN0aW9uSWR4ID4gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmwgKyAnJicgKyBxdWVyeVBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChxdWVyeVBhcmFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybCArICc/JyArIHF1ZXJ5UGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmw7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgdXJsID0gZ2V0RmluYWxVcmwocGFyYW1zKTtcbiAgICAgICAgICAgICAgICAvLyBXZSBtdXN0IHNwbGl0IHRoZSBHRVQgaW4gbXVsdGlwbGUgc2hvcnQgVVJMJ3NcbiAgICAgICAgICAgICAgICAvLyBUaGUgb25seSBwcm9wZXJ0eSBhbGxvd2VkIHRvIGJlIHNwbGl0IGlzIFwiaW5jbHVkZVwiXG4gICAgICAgICAgICAgICAgaWYgKHBhcmFtcyAmJiBwYXJhbXMuaW5jbHVkZSAmJiB1cmwubGVuZ3RoID4gTUFYX1VSTF9MRU5HVEgpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmFtc0NvcHkgPSAkLmV4dGVuZCh0cnVlLCB7fSwgcGFyYW1zKTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHBhcmFtc0NvcHkuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybE5vSW5jbHVkZXMgPSBnZXRGaW5hbFVybChwYXJhbXNDb3B5KTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRpZmYgPSBNQVhfVVJMX0xFTkdUSCAtIHVybE5vSW5jbHVkZXMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IG9wdGlvbnMuc3VjY2VzcyB8fCBodHRwT3B0aW9ucy5zdWNjZXNzIHx8ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZEVycm9yID0gb3B0aW9ucy5lcnJvciB8fCBodHRwT3B0aW9ucy5lcnJvciB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSB0aGUgb3JpZ2luYWwgc3VjY2VzcyBhbmQgZXJyb3IgY2FsbGJhY2tzXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuc3VjY2VzcyA9ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvciA9ICQubm9vcDtcblxuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZSA9IHBhcmFtcy5pbmNsdWRlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VyckluY2x1ZGVzID0gW107XG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmNsdWRlT3B0cyA9IFtjdXJySW5jbHVkZXNdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHZhcmlhYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgYSBncmVlZHkgYXBwcm9hY2ggZm9yIG5vdywgY2FuIGJlIG9wdGltaXplZCB0byBiZSBzb2x2ZWQgaW4gYSBtb3JlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBlZmZpY2llbnQgd2F5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyArIDEgaXMgdGhlIGNvbW1hXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3Vyckxlbmd0aCArIHZhcmlhYmxlLmxlbmd0aCArIDEgPCBkaWZmKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzLnB1c2godmFyaWFibGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJMZW5ndGggKz0gdmFyaWFibGUubGVuZ3RoICsgMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzID0gW3ZhcmlhYmxlXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlT3B0cy5wdXNoKGN1cnJJbmNsdWRlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aCArIHZhcmlhYmxlLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB2YXIgcmVxcyA9ICQubWFwKGluY2x1ZGVPcHRzLCBmdW5jdGlvbiAoaW5jbHVkZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlcVBhcmFtcyA9ICQuZXh0ZW5kKHt9LCBwYXJhbXMsIHsgaW5jbHVkZTogaW5jbHVkZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChyZXFQYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgJC53aGVuLmFwcGx5KCQsIHJlcXMpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRWFjaCBhcmd1bWVudCBhcmUgYXJyYXlzIG9mIHRoZSBhcmd1bWVudHMgb2YgZWFjaCBkb25lIHJlcXVlc3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgZmlyc3QgYXJyYXkgb2YgYXJndW1lbnRzIGlzIHRoZSBkYXRhXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNWYWxpZCA9IGFyZ3VtZW50c1swXSAmJiBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaG91bGQgbmV2ZXIgaGFwcGVuLi4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpcnN0UmVzcG9uc2UgPSBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNSdW5BUEkgPSAoaXNPYmplY3QgJiYgJC5pc1BsYWluT2JqZWN0KGZpcnN0UmVzcG9uc2UudmFyaWFibGVzKSkgfHwgIWlzT2JqZWN0O1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzUnVuQVBJKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzT2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnZ3JlZ2F0ZSB0aGUgdmFyaWFibGVzIHByb3BlcnR5IG9ubHlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZVJ1biA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJ1biA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVSdW4udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZVJ1biwgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFycmF5IG9mIHJ1bnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWdyZWdhdGUgdmFyaWFibGVzIGluIGVhY2ggcnVuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkUnVucyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVucyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISQuaXNBcnJheShydW5zKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChydW5zLCBmdW5jdGlvbiAoaWR4UnVuLCBydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocnVuLmlkICYmICFhZ2dyZWdhdGVkUnVuc1tydW4uaWRdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bi52YXJpYWJsZXMgPSBydW4udmFyaWFibGVzIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVuc1tydW4uaWRdID0gcnVuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocnVuLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHR1cm4gaXQgaW50byBhbiBhcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVucyA9ICQubWFwKGFnZ3JlZ2F0ZWRSdW5zLCBmdW5jdGlvbiAocnVuKSB7IHJldHVybiBydW47IH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyB2YXJpYWJsZXMgQVBJXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSByZXNwb25zZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkVmFyaWFibGVzID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFycyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIHZhcnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IuYXBwbHkoaHR0cCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZWplY3QuYXBwbHkoZHRkLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuIl19 diff --git a/dist/epicenter.min.js b/dist/epicenter.min.js index 190b7748..98e39325 100644 --- a/dist/epicenter.min.js +++ b/dist/epicenter.min.js @@ -17,7 +17,7 @@ var F={util:{},factory:{},transport:{},store:{},service:{},manager:{strategy:{}} }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./api-version.json":5,"./managers/auth-manager":7,"./managers/epicenter-channel-manager":9,"./managers/run-manager":11,"./managers/run-strategies/always-new-strategy":12,"./managers/run-strategies/conditional-creation-strategy":13,"./managers/run-strategies/identity-strategy":14,"./managers/run-strategies/new-if-initialized-strategy":16,"./managers/run-strategies/new-if-missing-strategy":17,"./managers/run-strategies/new-if-persisted-strategy":18,"./managers/scenario-manager":21,"./managers/world-manager":23,"./service/admin-file-service":24,"./service/asset-api-adapter":25,"./service/auth-api-service":26,"./service/channel-service":27,"./service/configuration-service":28,"./service/data-api-service":29,"./service/member-api-adapter":30,"./service/run-api-service":31,"./service/state-api-adapter":32,"./service/url-config-service":33,"./service/user-api-adapter":34,"./service/variables-api-service":35,"./service/world-api-adapter":36,"./store/cookie-store":37,"./store/store-factory":38,"./transport/ajax-http-transport":39,"./transport/http-transport-factory":40,"./util/inherit":41,"./util/make-sequence":42,"./util/query-util":44,"./util/run-util":45}],7:[function(require,module,exports){ -"use strict";function saveSession(userInfo,store){var serialized=JSON.stringify(userInfo);store.set(EPI_SESSION_KEY,serialized),store.set(EPI_COOKIE_KEY,userInfo.auth_token)}function getSession(store){var session=store.get(EPI_SESSION_KEY)||"{}";return JSON.parse(session)}function AuthManager(options){this.options=$.extend(!0,{},defaults,options);var urlConfig=new ConfigService(this.options).get("server");this.isLocal=urlConfig.isLocalhost(),this.options.account||(this.options.account=urlConfig.accountPath),void 0===this.options.project&&(this.options.project=urlConfig.projectPath),this.store=new StorageFactory(this.options.store),session=getSession(this.store),token=this.store.get(EPI_COOKIE_KEY)||"",this.authAdapter=new AuthAdapter(this.options,{token:session.auth_token})}var ConfigService=require("../service/configuration-service");var AuthAdapter=require("../service/auth-api-service");var MemberAdapter=require("../service/member-api-adapter");var StorageFactory=require("../store/store-factory");var Buffer=require("buffer").Buffer;var keyNames=require("./key-names");var defaults={store:{synchronous:!0}};var EPI_COOKIE_KEY=keyNames.EPI_COOKIE_KEY;var EPI_SESSION_KEY=keyNames.EPI_SESSION_KEY;var store;var token;var session;var _findUserInGroup=function(members,id){for(var j=0;j1&&groupId){var filteredGroups=$.grep(memberInfo,function(resGroup){return resGroup.groupId===groupId});group=1===filteredGroups.length?filteredGroups[0]:null}if(group){var groupSelection=group.groupId;data.groupSelection[adapterOptions.project]=groupSelection;var sessionInfoWithGroup=$.extend({},sessionInfo,{groupId:group.groupId,groupName:group.name,isFac:"facilitator"===_findUserInGroup(group.members,userInfo.user_id).role});saveSession(sessionInfoWithGroup,_this.store),outSuccess.apply(this,[data]),$d.resolve(data)}else handleGroupError("This user is associated with more than one group. Please specify a group id to log into and try again",403,data)}).fail($d.reject)};return adapterOptions.success=handleSuccess,adapterOptions.error=function(response){return adapterOptions.account?(adapterOptions.account=null,adapterOptions.error=function(){outError.apply(this,arguments),$d.reject(response)},void _this.authAdapter.login(adapterOptions)):(outError.apply(this,arguments),void $d.reject(response))},this.authAdapter.login(adapterOptions),$d.promise()},logout:function(options){var adapterOptions=$.extend(!0,{token:token},this.options,options);var removeCookieFn=function(response){store.remove(EPI_COOKIE_KEY,adapterOptions),store.remove(EPI_SESSION_KEY,adapterOptions),token=""};return this.authAdapter.logout(adapterOptions).done(removeCookieFn)},getToken:function(options){var httpOptions=$.extend(!0,this.options,options);var $d=$.Deferred();return token?$d.resolve(token):this.login(httpOptions).then($d.resolve),$d.promise()},getUserGroups:function(params,options){var adapterOptions=$.extend(!0,{success:$.noop},this.options,options);var $d=$.Deferred();var outSuccess=adapterOptions.success;adapterOptions.success=function(memberInfo){adapterOptions.project&&(memberInfo=$.grep(memberInfo,function(group){return group.project===adapterOptions.project})),outSuccess.apply(this,[memberInfo]),$d.resolve(memberInfo)};var memberAdapter=new MemberAdapter({token:params.token});return memberAdapter.getGroupsForUser(params,adapterOptions).fail($d.reject),$d.promise()},getCurrentUserSessionInfo:function(options){return getSession(this.store,options)}}),module.exports=AuthManager; +"use strict";function saveSession(userInfo,store){var serialized=JSON.stringify(userInfo);store.set(EPI_SESSION_KEY,serialized),store.set(EPI_COOKIE_KEY,userInfo.auth_token)}function getSession(store){var session=store.get(EPI_SESSION_KEY)||"{}";return JSON.parse(session)}function AuthManager(options){this.options=$.extend(!0,{},defaults,options);var urlConfig=new ConfigService(this.options).get("server");this.isLocal=urlConfig.isLocalhost(),this.options.account||(this.options.account=urlConfig.accountPath),void 0===this.options.project&&(this.options.project=urlConfig.projectPath),this.store=new StorageFactory(this.options.store),session=getSession(this.store),token=this.store.get(EPI_COOKIE_KEY)||"",this.authAdapter=new AuthAdapter(this.options,{token:session.auth_token})}var ConfigService=require("../service/configuration-service");var AuthAdapter=require("../service/auth-api-service");var MemberAdapter=require("../service/member-api-adapter");var StorageFactory=require("../store/store-factory");var Buffer=require("buffer").Buffer;var keyNames=require("./key-names");var defaults={store:{synchronous:!0}};var EPI_COOKIE_KEY=keyNames.EPI_COOKIE_KEY;var EPI_SESSION_KEY=keyNames.EPI_SESSION_KEY;var token;var session;var _findUserInGroup=function(members,id){for(var j=0;j1&&groupId){var filteredGroups=$.grep(memberInfo,function(resGroup){return resGroup.groupId===groupId});group=1===filteredGroups.length?filteredGroups[0]:null}if(group){var groupSelection=group.groupId;data.groupSelection[adapterOptions.project]=groupSelection;var sessionInfoWithGroup=$.extend({},sessionInfo,{groupId:group.groupId,groupName:group.name,isFac:"facilitator"===_findUserInGroup(group.members,userInfo.user_id).role});saveSession(sessionInfoWithGroup,_this.store),outSuccess.apply(this,[data]),$d.resolve(data)}else handleGroupError("This user is associated with more than one group. Please specify a group id to log into and try again",403,data)}).fail($d.reject)};return adapterOptions.success=handleSuccess,adapterOptions.error=function(response){return adapterOptions.account?(adapterOptions.account=null,adapterOptions.error=function(){outError.apply(this,arguments),$d.reject(response)},void _this.authAdapter.login(adapterOptions)):(outError.apply(this,arguments),void $d.reject(response))},this.authAdapter.login(adapterOptions),$d.promise()},logout:function(options){var _this=this;var adapterOptions=$.extend(!0,{token:token},this.options,options);var removeCookieFn=function(response){_this.store.remove(EPI_COOKIE_KEY,adapterOptions),_this.store.remove(EPI_SESSION_KEY,adapterOptions),token=""};return this.authAdapter.logout(adapterOptions).done(removeCookieFn)},getToken:function(options){var httpOptions=$.extend(!0,this.options,options);var $d=$.Deferred();return token?$d.resolve(token):this.login(httpOptions).then($d.resolve),$d.promise()},getUserGroups:function(params,options){var adapterOptions=$.extend(!0,{success:$.noop},this.options,options);var $d=$.Deferred();var outSuccess=adapterOptions.success;adapterOptions.success=function(memberInfo){adapterOptions.project&&(memberInfo=$.grep(memberInfo,function(group){return group.project===adapterOptions.project})),outSuccess.apply(this,[memberInfo]),$d.resolve(memberInfo)};var memberAdapter=new MemberAdapter({token:params.token});return memberAdapter.getGroupsForUser(params,adapterOptions).fail($d.reject),$d.promise()},getCurrentUserSessionInfo:function(options){return getSession(this.store,options)}}),module.exports=AuthManager; },{"../service/auth-api-service":26,"../service/configuration-service":28,"../service/member-api-adapter":30,"../store/store-factory":38,"./key-names":10,"buffer":1}],8:[function(require,module,exports){ "use strict";var Channel=require("../service/channel-service");var ChannelManager=function(options){if(!$.cometd)throw new Error("Cometd library not found. Please include epicenter-multiplayer-dependencies.js");if(!options||!options.url)throw new Error("Please provide an url for the cometd server");var defaults={url:"",logLevel:"info",websocketEnabled:!1,shareConnection:!1,channel:{}};var defaultCometOptions=$.extend(!0,{},defaults,options);if(this.currentSubscriptions=[],this.options=defaultCometOptions,defaultCometOptions.shareConnection&&ChannelManager.prototype._cometd)return this.cometd=ChannelManager.prototype._cometd,this;var cometd=new $.Cometd;ChannelManager.prototype._cometd=cometd,cometd.websocketEnabled=defaultCometOptions.websocketEnabled,this.isConnected=!1;var connectionBroken=function(message){$(this).trigger("disconnect",message)};var connectionSucceeded=function(message){$(this).trigger("connect",message)};var me=this;cometd.configure(defaultCometOptions),cometd.addListener("/meta/connect",function(message){var wasConnected=this.isConnected;this.isConnected=message.successful===!0,!wasConnected&&this.isConnected?connectionSucceeded.call(this,message):wasConnected&&!this.isConnected&&connectionBroken.call(this,message)}.bind(this)),cometd.addListener("/meta/disconnect",connectionBroken),cometd.addListener("/meta/handshake",function(message){message.successful&&cometd.batch(function(){$(me.currentSubscriptions).each(function(index,subs){cometd.resubscribe(subs)})})}),cometd.addListener("/meta/subscribe",function(message){$(me).trigger("subscribe",message)}),cometd.addListener("/meta/unsubscribe",function(message){$(me).trigger("unsubscribe",message)}),cometd.addListener("/meta/publish",function(message){$(me).trigger("publish",message)}),cometd.addListener("/meta/unsuccessful",function(message){$(me).trigger("error",message)}),cometd.handshake(),this.cometd=cometd};ChannelManager.prototype=$.extend(ChannelManager.prototype,{getChannel:function(options){options&&!$.isPlainObject(options)&&(options={base:options});var defaults={transport:this.cometd};var channel=new Channel($.extend(!0,{},this.options.channel,defaults,options));var subs=channel.subscribe;channel.subscribe=function(){var subid=subs.apply(channel,arguments);return this.currentSubscriptions=this.currentSubscriptions.concat(subid),subid}.bind(this);var unsubs=channel.unsubscribe;return channel.unsubscribe=function(){var removed=unsubs.apply(channel,arguments);for(var i=0;i\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && url.length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = '?include='.length;\n var variable = include.pop();\n while (variable) {\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + variable.length + 1 < diff) {\n currIncludes.push(variable);\n currLength += variable.length + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + variable.length;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ##File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n // config || (config = configService.get());\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || store.get('epicenter.token') || '',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: '',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {String} `folderType` One of Model|Static|Node\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, folderType, options) {\n var path = folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ##Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * ##Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: '',\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n domain: 'forio.com',\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ##Authentication API Service\n *\n * The Authentication API Service provides methods for logging in and logging out. On login, this service creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n * auth.logout();\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n /**\n * Logs user out from specified accounts.\n * Epicenter logout is not implemented yet, added a dummy promise that gets automatically resolved.\n *\n * **Example**\n *\n * auth.logout();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ##World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n $.extend(params, _pick(serviceOptions, ['account', 'project', 'group']));\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ##State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ##User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ##Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: '',\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar keyNames = require('../managers/key-names');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n var session = JSON.parse(store.get(keyNames.EPI_SESSION_KEY) || '{}');\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get(keyNames.EPI_COOKIE_KEY) || '',\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: session.userId,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n var serviceOptions = $.extend(true, {}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.forio.com'\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n\n document.cookie = encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookieReg = new RegExp('(?:(?:^|.*;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$');\n var val = document.cookie.replace(cookieReg, '$1');\n val = decodeURIComponent(val) || null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n\n document.cookie = encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var aKeys = document.cookie.replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* ####Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar ConfigService = require('../service/configuration-service');\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar StorageFactory = require('../store/store-factory');\nvar Buffer = require('buffer').Buffer;\nvar keyNames = require('./key-names');\n\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY;\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar store;\nvar token;\nvar session;\n\nfunction saveSession(userInfo, store) {\n var serialized = JSON.stringify(userInfo);\n store.set(EPI_SESSION_KEY, serialized);\n\n //jshint camelcase: false\n //jscs:disable\n store.set(EPI_COOKIE_KEY, userInfo.auth_token);\n}\n\nfunction getSession(store) {\n var session = store.get(EPI_SESSION_KEY) || '{}';\n return JSON.parse(session);\n}\n\nfunction AuthManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n var urlConfig = new ConfigService(this.options).get('server');\n this.isLocal = urlConfig.isLocalhost();\n\n if (!this.options.account) {\n this.options.account = urlConfig.accountPath;\n }\n\n // null might specified to disable project filtering\n if (this.options.project === undefined) {\n this.options.project = urlConfig.projectPath;\n }\n\n this.store = new StorageFactory(this.options.store);\n session = getSession(this.store);\n token = this.store.get(EPI_COOKIE_KEY) || '';\n //jshint camelcase: false\n //jscs:disable\n this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token });\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(memberInfo, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n var groupSelection = group.groupId;\n data.groupSelection[adapterOptions.project] = groupSelection;\n var sessionInfoWithGroup = $.extend({}, sessionInfo, {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n });\n saveSession(sessionInfoWithGroup, _this.store);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n }).fail($d.reject);\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var adapterOptions = $.extend(true, { token: token }, this.options, options);\n\n var removeCookieFn = function (response) {\n store.remove(EPI_COOKIE_KEY, adapterOptions);\n store.remove(EPI_SESSION_KEY, adapterOptions);\n token = '';\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = $.extend(true, this.options, options);\n\n var $d = $.Deferred();\n if (token) {\n $d.resolve(token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = $.extend(true, { success: $.noop }, this.options, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return getSession(this.store, options);\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `server` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `server.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `server.project` Epicenter project id.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\n\nvar AuthManager = require('./auth-manager');\n\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n var userInfo = session.getCurrentUserSessionInfo();\n\n var defaults = {\n account: userInfo.account,\n project: userInfo.project,\n };\n var defaultCometOptions = $.extend(true, {}, defaults, userInfo, options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getDataChannel('survey-responses');\n * gc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionStore = require('../../store/store-factory');\nvar classFrom = require('../../util/inherit');\nvar UrlService = require('../../service/url-config-service');\nvar AuthManager = require('../auth-manager');\n\nvar sessionStore = new SessionStore({});\nvar urlService = new UrlService();\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, path) {\n if (!path) {\n if (!urlService.isLocalhost()) {\n path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/');\n // make sure we don't get consecuteive '/' so we have a valid path for the session\n path = path.replace(/\\/{2,}/g,'/');\n } else {\n path = '';\n }\n }\n // set the seesionKey for the run\n sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path });\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.options.path);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession);\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","'use strict';\n\nmodule.exports = {\n EPI_COOKIE_KEY: 'epicenter.project.token',\n EPI_SESSION_KEY: 'epicenter.user.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","'use strict';\n\nvar Channel = require('../service/channel-service');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n }\n };\n var defaultCometOptions = $.extend(true, {}, defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake();\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('is-array')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\nBuffer.poolSize = 8192 // not used by this implementation\n\nvar rootParent = {}\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property\n * on objects.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\nfunction typedArraySupport () {\n function Bar () {}\n try {\n var arr = new Uint8Array(1)\n arr.foo = function () { return 42 }\n arr.constructor = Bar\n return arr.foo() === 42 && // typed array instances can be augmented\n arr.constructor === Bar && // constructor can be set\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\n/**\n * Class: Buffer\n * =============\n *\n * The Buffer constructor returns instances of `Uint8Array` that are augmented\n * with function properties for all the node `Buffer` API functions. We use\n * `Uint8Array` so that square bracket notation works as expected -- it returns\n * a single octet.\n *\n * By augmenting the instances, we can avoid modifying the `Uint8Array`\n * prototype.\n */\nfunction Buffer (arg) {\n if (!(this instanceof Buffer)) {\n // Avoid going through an ArgumentsAdaptorTrampoline in the common case.\n if (arguments.length > 1) return new Buffer(arg, arguments[1])\n return new Buffer(arg)\n }\n\n this.length = 0\n this.parent = undefined\n\n // Common case.\n if (typeof arg === 'number') {\n return fromNumber(this, arg)\n }\n\n // Slightly less common case.\n if (typeof arg === 'string') {\n return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')\n }\n\n // Unusual.\n return fromObject(this, arg)\n}\n\nfunction fromNumber (that, length) {\n that = allocate(that, length < 0 ? 0 : checked(length) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < length; i++) {\n that[i] = 0\n }\n }\n return that\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'\n\n // Assumption: byteLength() return value is always < kMaxLength.\n var length = byteLength(string, encoding) | 0\n that = allocate(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromObject (that, object) {\n if (Buffer.isBuffer(object)) return fromBuffer(that, object)\n\n if (isArray(object)) return fromArray(that, object)\n\n if (object == null) {\n throw new TypeError('must start with number, buffer, array or string')\n }\n\n if (typeof ArrayBuffer !== 'undefined') {\n if (object.buffer instanceof ArrayBuffer) {\n return fromTypedArray(that, object)\n }\n if (object instanceof ArrayBuffer) {\n return fromArrayBuffer(that, object)\n }\n }\n\n if (object.length) return fromArrayLike(that, object)\n\n return fromJsonObject(that, object)\n}\n\nfunction fromBuffer (that, buffer) {\n var length = checked(buffer.length) | 0\n that = allocate(that, length)\n buffer.copy(that, 0, 0, length)\n return that\n}\n\nfunction fromArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Duplicate of fromArray() to keep fromArray() monomorphic.\nfunction fromTypedArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n // Truncating the elements is probably not what people expect from typed\n // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior\n // of the old Buffer constructor.\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n array.byteLength\n that = Buffer._augment(new Uint8Array(array))\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromTypedArray(that, new Uint8Array(array))\n }\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.\n// Returns a zero-length buffer for inputs that don't conform to the spec.\nfunction fromJsonObject (that, object) {\n var array\n var length = 0\n\n if (object.type === 'Buffer' && isArray(object.data)) {\n array = object.data\n length = checked(array.length) | 0\n }\n that = allocate(that, length)\n\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n}\n\nfunction allocate (that, length) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = Buffer._augment(new Uint8Array(length))\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that.length = length\n that._isBuffer = true\n }\n\n var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1\n if (fromPool) that.parent = rootParent\n\n return that\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (subject, encoding) {\n if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)\n\n var buf = new Buffer(subject, encoding)\n delete buf.parent\n return buf\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n var i = 0\n var len = Math.min(x, y)\n while (i < len) {\n if (a[i] !== b[i]) break\n\n ++i\n }\n\n if (i !== len) {\n x = a[i]\n y = b[i]\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')\n\n if (list.length === 0) {\n return new Buffer(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; i++) {\n length += list[i].length\n }\n }\n\n var buf = new Buffer(length)\n var pos = 0\n for (i = 0; i < list.length; i++) {\n var item = list[i]\n item.copy(buf, pos)\n pos += item.length\n }\n return buf\n}\n\nfunction byteLength (string, encoding) {\n if (typeof string !== 'string') string = '' + string\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n // Deprecated\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\n// pre-set for values that may exist in the future\nBuffer.prototype.length = undefined\nBuffer.prototype.parent = undefined\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n start = start | 0\n end = end === undefined || end === Infinity ? this.length : end | 0\n\n if (!encoding) encoding = 'utf8'\n if (start < 0) start = 0\n if (end > this.length) end = this.length\n if (end <= start) return ''\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return 0\n return Buffer.compare(this, b)\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset) {\n if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff\n else if (byteOffset < -0x80000000) byteOffset = -0x80000000\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n if (val.length === 0) return -1 // special case: looking for empty string always fails\n return String.prototype.indexOf.call(this, val, byteOffset)\n }\n if (Buffer.isBuffer(val)) {\n return arrayIndexOf(this, val, byteOffset)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset)\n }\n\n function arrayIndexOf (arr, val, byteOffset) {\n var foundIndex = -1\n for (var i = 0; byteOffset + i < arr.length; i++) {\n if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex\n } else {\n foundIndex = -1\n }\n }\n return -1\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\n// `get` is deprecated\nBuffer.prototype.get = function get (offset) {\n console.log('.get() is deprecated. Access using array indexes instead.')\n return this.readUInt8(offset)\n}\n\n// `set` is deprecated\nBuffer.prototype.set = function set (v, offset) {\n console.log('.set() is deprecated. Access using array indexes instead.')\n return this.writeUInt8(v, offset)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; i++) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) throw new Error('Invalid hex string')\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n var swap = encoding\n encoding = offset\n offset = length | 0\n length = swap\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; i++) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = Buffer._augment(this.subarray(start, end))\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; i++) {\n newBuf[i] = this[i + start]\n }\n }\n\n if (newBuf.length) newBuf.parent = this.parent || this\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n if (offset < 0) throw new RangeError('index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; i--) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; i++) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n target._set(this.subarray(start, start + len), targetStart)\n }\n\n return len\n}\n\n// fill(value, start=0, end=buffer.length)\nBuffer.prototype.fill = function fill (value, start, end) {\n if (!value) value = 0\n if (!start) start = 0\n if (!end) end = this.length\n\n if (end < start) throw new RangeError('end < start')\n\n // Fill 0 bytes; we're done\n if (end === start) return\n if (this.length === 0) return\n\n if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')\n if (end < 0 || end > this.length) throw new RangeError('end out of bounds')\n\n var i\n if (typeof value === 'number') {\n for (i = start; i < end; i++) {\n this[i] = value\n }\n } else {\n var bytes = utf8ToBytes(value.toString())\n var len = bytes.length\n for (i = start; i < end; i++) {\n this[i] = bytes[i % len]\n }\n }\n\n return this\n}\n\n/**\n * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.\n * Added in Node 0.12. Only available in browsers that support ArrayBuffer.\n */\nBuffer.prototype.toArrayBuffer = function toArrayBuffer () {\n if (typeof Uint8Array !== 'undefined') {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n return (new Buffer(this)).buffer\n } else {\n var buf = new Uint8Array(this.length)\n for (var i = 0, len = buf.length; i < len; i += 1) {\n buf[i] = this[i]\n }\n return buf.buffer\n }\n } else {\n throw new TypeError('Buffer.toArrayBuffer not supported in this browser')\n }\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar BP = Buffer.prototype\n\n/**\n * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods\n */\nBuffer._augment = function _augment (arr) {\n arr.constructor = Buffer\n arr._isBuffer = true\n\n // save reference to original Uint8Array set method before overwriting\n arr._set = arr.set\n\n // deprecated\n arr.get = BP.get\n arr.set = BP.set\n\n arr.write = BP.write\n arr.toString = BP.toString\n arr.toLocaleString = BP.toString\n arr.toJSON = BP.toJSON\n arr.equals = BP.equals\n arr.compare = BP.compare\n arr.indexOf = BP.indexOf\n arr.copy = BP.copy\n arr.slice = BP.slice\n arr.readUIntLE = BP.readUIntLE\n arr.readUIntBE = BP.readUIntBE\n arr.readUInt8 = BP.readUInt8\n arr.readUInt16LE = BP.readUInt16LE\n arr.readUInt16BE = BP.readUInt16BE\n arr.readUInt32LE = BP.readUInt32LE\n arr.readUInt32BE = BP.readUInt32BE\n arr.readIntLE = BP.readIntLE\n arr.readIntBE = BP.readIntBE\n arr.readInt8 = BP.readInt8\n arr.readInt16LE = BP.readInt16LE\n arr.readInt16BE = BP.readInt16BE\n arr.readInt32LE = BP.readInt32LE\n arr.readInt32BE = BP.readInt32BE\n arr.readFloatLE = BP.readFloatLE\n arr.readFloatBE = BP.readFloatBE\n arr.readDoubleLE = BP.readDoubleLE\n arr.readDoubleBE = BP.readDoubleBE\n arr.writeUInt8 = BP.writeUInt8\n arr.writeUIntLE = BP.writeUIntLE\n arr.writeUIntBE = BP.writeUIntBE\n arr.writeUInt16LE = BP.writeUInt16LE\n arr.writeUInt16BE = BP.writeUInt16BE\n arr.writeUInt32LE = BP.writeUInt32LE\n arr.writeUInt32BE = BP.writeUInt32BE\n arr.writeIntLE = BP.writeIntLE\n arr.writeIntBE = BP.writeIntBE\n arr.writeInt8 = BP.writeInt8\n arr.writeInt16LE = BP.writeInt16LE\n arr.writeInt16BE = BP.writeInt16BE\n arr.writeInt32LE = BP.writeInt32LE\n arr.writeInt32BE = BP.writeInt32BE\n arr.writeFloatLE = BP.writeFloatLE\n arr.writeFloatBE = BP.writeFloatBE\n arr.writeDoubleLE = BP.writeDoubleLE\n arr.writeDoubleBE = BP.writeDoubleBE\n arr.fill = BP.fill\n arr.inspect = BP.inspect\n arr.toArrayBuffer = BP.toArrayBuffer\n\n return arr\n}\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; i++) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; i++) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n;(function (exports) {\n\t'use strict';\n\n var Arr = (typeof Uint8Array !== 'undefined')\n ? Uint8Array\n : Array\n\n\tvar PLUS = '+'.charCodeAt(0)\n\tvar SLASH = '/'.charCodeAt(0)\n\tvar NUMBER = '0'.charCodeAt(0)\n\tvar LOWER = 'a'.charCodeAt(0)\n\tvar UPPER = 'A'.charCodeAt(0)\n\tvar PLUS_URL_SAFE = '-'.charCodeAt(0)\n\tvar SLASH_URL_SAFE = '_'.charCodeAt(0)\n\n\tfunction decode (elt) {\n\t\tvar code = elt.charCodeAt(0)\n\t\tif (code === PLUS ||\n\t\t code === PLUS_URL_SAFE)\n\t\t\treturn 62 // '+'\n\t\tif (code === SLASH ||\n\t\t code === SLASH_URL_SAFE)\n\t\t\treturn 63 // '/'\n\t\tif (code < NUMBER)\n\t\t\treturn -1 //no match\n\t\tif (code < NUMBER + 10)\n\t\t\treturn code - NUMBER + 26 + 26\n\t\tif (code < UPPER + 26)\n\t\t\treturn code - UPPER\n\t\tif (code < LOWER + 26)\n\t\t\treturn code - LOWER + 26\n\t}\n\n\tfunction b64ToByteArray (b64) {\n\t\tvar i, j, l, tmp, placeHolders, arr\n\n\t\tif (b64.length % 4 > 0) {\n\t\t\tthrow new Error('Invalid string. Length must be a multiple of 4')\n\t\t}\n\n\t\t// the number of equal signs (place holders)\n\t\t// if there are two placeholders, than the two characters before it\n\t\t// represent one byte\n\t\t// if there is only one, then the three characters before it represent 2 bytes\n\t\t// this is just a cheap hack to not do indexOf twice\n\t\tvar len = b64.length\n\t\tplaceHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0\n\n\t\t// base64 is 4/3 + up to two characters of the original data\n\t\tarr = new Arr(b64.length * 3 / 4 - placeHolders)\n\n\t\t// if there are placeholders, only get up to the last complete 4 chars\n\t\tl = placeHolders > 0 ? b64.length - 4 : b64.length\n\n\t\tvar L = 0\n\n\t\tfunction push (v) {\n\t\t\tarr[L++] = v\n\t\t}\n\n\t\tfor (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))\n\t\t\tpush((tmp & 0xFF0000) >> 16)\n\t\t\tpush((tmp & 0xFF00) >> 8)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\tif (placeHolders === 2) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)\n\t\t\tpush(tmp & 0xFF)\n\t\t} else if (placeHolders === 1) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)\n\t\t\tpush((tmp >> 8) & 0xFF)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\treturn arr\n\t}\n\n\tfunction uint8ToBase64 (uint8) {\n\t\tvar i,\n\t\t\textraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes\n\t\t\toutput = \"\",\n\t\t\ttemp, length\n\n\t\tfunction encode (num) {\n\t\t\treturn lookup.charAt(num)\n\t\t}\n\n\t\tfunction tripletToBase64 (num) {\n\t\t\treturn encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)\n\t\t}\n\n\t\t// go through the array every three bytes, we'll deal with trailing stuff later\n\t\tfor (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n\t\t\ttemp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n\t\t\toutput += tripletToBase64(temp)\n\t\t}\n\n\t\t// pad the end with zeros, but make sure to not forget the extra bytes\n\t\tswitch (extraBytes) {\n\t\t\tcase 1:\n\t\t\t\ttemp = uint8[uint8.length - 1]\n\t\t\t\toutput += encode(temp >> 2)\n\t\t\t\toutput += encode((temp << 4) & 0x3F)\n\t\t\t\toutput += '=='\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\ttemp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])\n\t\t\t\toutput += encode(temp >> 10)\n\t\t\t\toutput += encode((temp >> 4) & 0x3F)\n\t\t\t\toutput += encode((temp << 2) & 0x3F)\n\t\t\t\toutput += '='\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn output\n\t}\n\n\texports.toByteArray = b64ToByteArray\n\texports.fromByteArray = uint8ToBase64\n}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))\n","\n/**\n * isArray\n */\n\nvar isArray = Array.isArray;\n\n/**\n * toString\n */\n\nvar str = Object.prototype.toString;\n\n/**\n * Whether or not the given `val`\n * is an array.\n *\n * example:\n *\n * isArray([]);\n * // > true\n * isArray(arguments);\n * // > false\n * isArray('');\n * // > false\n *\n * @param {mixed} val\n * @return {bool}\n */\n\nmodule.exports = isArray || function (val) {\n return !! val && '[object Array]' == str.call(val);\n};\n"]} \ No newline at end of file +{"version":3,"sources":["node_modules/grunt-browserify/node_modules/browserify/node_modules/browser-pack/_prelude.js","src/api-version.json","src/app.js","src/util/query-util.js","src/util/make-sequence.js","src/util/run-util.js","src/util/inherit.js","src/transport/http-transport-factory.js","src/transport/ajax-http-transport.js","src/service/url-config-service.js","src/service/configuration-service.js","src/service/run-api-service.js","src/service/admin-file-service.js","src/service/variables-api-service.js","src/service/data-api-service.js","src/service/auth-api-service.js","src/service/state-api-adapter.js","src/service/world-api-adapter.js","src/service/user-api-adapter.js","src/service/member-api-adapter.js","src/service/asset-api-adapter.js","src/store/cookie-store.js","src/store/store-factory.js","src/managers/scenario-manager.js","src/managers/run-manager.js","src/managers/auth-manager.js","src/managers/world-manager.js","src/managers/epicenter-channel-manager.js","src/service/channel-service.js","src/managers/run-strategies/always-new-strategy.js","src/managers/run-strategies/conditional-creation-strategy.js","src/managers/run-strategies/identity-strategy.js","src/managers/run-strategies/new-if-missing-strategy.js","src/managers/run-strategies/new-if-persisted-strategy.js","src/managers/run-strategies/new-if-initialized-strategy.js","src/util/object-util.js","src/managers/key-names.js","src/managers/special-operations.js","src/managers/channel-manager.js","src/managers/run-strategies/strategies-map.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/index.js","src/managers/run-strategies/multiplayer-strategy.js","src/managers/run-strategies/persistent-single-player-strategy.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/ieee754/index.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/base64-js/lib/b64.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/is-array/index.js"],"names":["F","util","factory","transport","store","service","manager","strategy","query","require","makeSequence","run","classFrom","Transport","Ajax","URL","Config","Run","File","Variables","Data","Auth","World","State","User","Member","Asset","Cookie","Store","ScenarioManager","RunManager","AuthManager","WorldManager","identity","ChannelManager","Channel","version","api","global","module","exports","toMatrixFormat","qs","undefined","String","returnArray","OPERATORS","$","each","key","value","inArray","trim","charAt","push","mtrx","join","toQueryFormat","isArray","isPlainObject","JSON","stringify","result","qsToObject","qsArray","split","returnObj","index","qKey","qVal","indexOf","mergeQS","qs1","qs2","obj1","this","obj2","extend","addTrailingSlash","url","length","_w","val","then","p","Deferred","resolve","promise","seq","next","cur","list","splice","Array","prototype","slice","apply","arguments","seed","fail","MakeSeq","obj","res","__calls","original","fn","start","_this","funcMaker","bind","args","Function","concat","prop","qutil","MAX_URL_LENGTH","normalizeOperations","operations","returnList","ops","_concat","arr","_normalizePlainObjects","opn","arg","_normalizeStructuredObjects","operation","name","params","_normalizeObject","_normalizeLiterals","_normalizeArrays","splitGetFactory","httpOptions","options","http","getValue","getFinalUrl","data","replace","queryParams","questionIdx","include","dtd","paramsCopy","urlNoIncludes","diff","oldSuccess","success","noop","oldError","error","currIncludes","includeOpts","currLength","variable","pop","reqs","map","reqParams","get","when","isValid","reject","firstResponse","isObject","isRunAPI","variables","aggregateRun","idx","aggregatedRuns","runs","idxRun","id","aggregatedVariables","vars","inherit","C","P","__super","constructor","dest","call","current","j","base","props","staticProps","parent","child","hasOwnProperty","qutils","config","defaults","contentType","headers","statusCode",404,"parameterParser","xhrFields","withCredentials","transportOptions","d","isFunction","connect","method","connectOptions","type","ALLOWED_TO_BE_FUNCTIONS","logLevel","console","log","oldSuccessFn","response","ajaxStatus","ajaxReq","beforeSend","xhr","settings","requestUrl","ajax","publicAPI","ajaxOptions","splitGet","post","patch","put","delete","delimiter","head","epiVersion","API_PROTOCOL","HOST_API_MAPPING","forio.com","foriodev.com","publicExports","protocol","host","window","location","appPath","path","pathname","accountPath","accnt","projectPath","prj","versionPath","isLocalhost","getAPIPath","PROJECT_APIS","apiPath","urlService","serviceOptions","server","setEnv","env","property","set","ConfigService","StorageFactory","rutil","_pick","TransportFactory","VariablesService","synchronous","token","account","project","filter","autoRestore","urlConfig","getFilterURL","addAutoRestoreHeader","isFilterRunId","autorestoreOpts","X-AutoRestore","Authorization","setFilterOrThrowError","Error","publicAsyncAPI","create","createOptions","runApiParams","model","outputModifier","load","runID","filters","save","attributes","do","opsArgs","postOptions","prms","serial","opParams","me","$d","doSingleOp","op","shift","parallel","queue","i","done","publicSyncAPI","getCurrentConfig","vs","runService","getContents","filePath","folderType","getURL","attrs","root","domain","q","saveAs","remove","keys","userName","password","login","resp","status","statusMessage","postParams","logout","apiEndpoint","parseRunIdOrError","runId","replay","replayOptions","action","clone","apiBase","assignmentEndpoint","projectEndpoint","group","setIdFilterOrThrowError","validateModelOrThrowError","worldApiParams","update","whitelist","updateOptions","deleteOptions","updateConfig","getOptions","getWorldsForUser","userId","worldId","addUsers","users","u","updateUser","user","patchOptions","removeUser","getCurrentRunId","getCurrentWorldForUser","groupName","worlds","sort","a","b","Date","lastModified","currentWorld","deleteRun","newRunForWorld","currentRunOptions","autoAssign","opt","maxUsers","getProjectSettings","toQFilter","toIdFilters","getFilters","threshold","getById","groupId","getFinalParams","patchUserActiveField","active","getGroupsForUser","isString","objParams","getParms","getGroupDetails","makeUserActive","makeUserInactive","keyNames","session","parse","EPI_SESSION_KEY","EPI_COOKIE_KEY","scope","fullUrl","processData","assetApiParams","scopeConfig","validateFilename","filename","validateUrlParams","partKeys","buildUrl","parts","upload","toLowerCase","FormData","urlOptions","getServiceOptions","files","fullPathFiles","file","assetUrl","setOptions","document","cookie","encodeURIComponent","cookieReg","RegExp","decodeURIComponent","remOptions","destroy","aKeys","nIdx","cookieKey","RunService","validFilter","saved","getRuns","loadVariables","meta","_getService","archive","getRun","patchRunService","patched","orig","reservedOps","Object","specialOperations","StrategyCtor","strategiesMap","reset","runServiceOptions","saveSession","userInfo","serialized","auth_token","getSession","isLocal","authAdapter","AuthAdapter","MemberAdapter","Buffer","_findUserInGroup","members","adapterOptions","outSuccess","outError","accountName","projectName","decodeToken","encoded","decode","atob","toString","handleGroupError","message","statusText","handleSuccess","access_token","userGroupOpts","getUserGroups","user_id","memberInfo","auth","userGroups","groupSelection","sessionInfo","filteredGroups","grep","resGroup","sessionInfoWithGroup","isFac","role","removeCookieFn","getToken","memberAdapter","getCurrentUserSessionInfo","buildStrategy","worldApi","WorldApi","world","_auth","getCurrentWorld","getCurrentRun","getAndRestoreLatestRun","currentWorldId","runOpts","rm","curUserId","curGroupName","getFromSettingsOrSessionOrError","sessionKeyName","EpicenterChannelManager","defaultCometOptions","urlOpts","getGroupChannel","baseTopic","getChannel","getWorldChannel","worldid","getUserChannel","userid","getPresenceChannel","channel","lastPingTime","PING_INTERVAL","subscribe","notification","incomingUserId","trigger","online","valueOf","setInterval","publish","now","getDataChannel","collection","oldsubs","topic","callback","context","callbackWithCleanData","payload","subType","date","actualData","topicResolver","channelOptions","makeName","channelName","newName","topics","subscriptionIds","opts","batch","returnObjs","warn","unsubscribe","on","event","off","ConditionalStrategy","Strategy","createIf","setRunInSession","sessionKey","sessionStore","makeSeq","Base","SessionStore","UrlService","STRATEGY_SESSION_KEY","condition","runOptions","runOptionsWithScope","userSession","freshlyCreated","runSession","_loadAndCheck","shouldCreate","msg","getResponseHeader","initialized","cometd","websocketEnabled","shareConnection","currentSubscriptions","_cometd","Cometd","isConnected","connectionBroken","connectionSucceeded","configure","addListener","wasConnected","successful","subs","resubscribe","handshake","subid","unsubs","removed","new-if-initialized","new-if-persisted","new-if-missing","always-new","multiplayer","persistent-single-player","none","typedArraySupport","Bar","Uint8Array","foo","subarray","byteLength","e","kMaxLength","TYPED_ARRAY_SUPPORT","fromNumber","fromString","fromObject","that","allocate","checked","string","encoding","write","object","isBuffer","fromBuffer","fromArray","TypeError","ArrayBuffer","buffer","fromTypedArray","fromArrayBuffer","fromArrayLike","fromJsonObject","copy","array","_augment","__proto__","_isBuffer","fromPool","poolSize","rootParent","RangeError","SlowBuffer","subject","buf","len","loweredCase","utf8ToBytes","base64ToBytes","slowToString","end","Infinity","hexSlice","utf8Slice","asciiSlice","binarySlice","base64Slice","utf16leSlice","hexWrite","offset","Number","remaining","strLen","parsed","parseInt","substr","isNaN","utf8Write","blitBuffer","asciiWrite","asciiToBytes","binaryWrite","base64Write","ucs2Write","utf16leToBytes","base64","fromByteArray","Math","min","firstByte","codePoint","bytesPerSequence","secondByte","thirdByte","fourthByte","tempCodePoint","decodeCodePointsArray","codePoints","MAX_ARGUMENTS_LENGTH","fromCharCode","ret","out","toHex","bytes","checkOffset","ext","checkInt","max","objectWriteUInt16","littleEndian","objectWriteUInt32","checkIEEE754","writeFloat","noAssert","ieee754","writeDouble","base64clean","str","stringtrim","INVALID_BASE64_RE","n","units","leadSurrogate","charCodeAt","byteArray","c","hi","lo","toByteArray","src","dst","INSPECT_MAX_BYTES","compare","x","y","isEncoding","pos","item","equals","inspect","match","byteOffset","arrayIndexOf","foundIndex","readUInt8","v","writeUInt8","isFinite","swap","toJSON","_arr","newBuf","sliceLen","readUIntLE","mul","readUIntBE","readUInt16LE","readUInt16BE","readUInt32LE","readUInt32BE","readIntLE","pow","readIntBE","readInt8","readInt16LE","readInt16BE","readInt32LE","readInt32BE","readFloatLE","read","readFloatBE","readDoubleLE","readDoubleBE","writeUIntLE","writeUIntBE","floor","writeUInt16LE","writeUInt16BE","writeUInt32LE","writeUInt32BE","writeIntLE","limit","sub","writeIntBE","writeInt8","writeInt16LE","writeInt16BE","writeInt32LE","writeInt32BE","writeFloatLE","writeFloatBE","writeDoubleLE","writeDoubleBE","target","targetStart","_set","fill","toArrayBuffer","BP","toLocaleString","IdentityStrategy","WorldApiAdapter","_loadRun","loadRunFromWorld","serverError","StateApi","_store","stateApi","_restoreRun","_getAllRuns","user.id","scope.group","dateComp","latestRun","shouldReplay","isLE","mLen","nBytes","m","eLen","eMax","eBias","nBits","s","NaN","rt","abs","LN2","lookup","elt","code","PLUS","PLUS_URL_SAFE","SLASH","SLASH_URL_SAFE","NUMBER","UPPER","LOWER","b64ToByteArray","b64","L","l","tmp","placeHolders","Arr","uint8ToBase64","uint8","encode","num","tripletToBase64","temp","extraBytes","output","base64js"],"mappings":"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","file":"bundle.js","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && url.length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = '?include='.length;\n var variable = include.pop();\n while (variable) {\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + variable.length + 1 < diff) {\n currIncludes.push(variable);\n currLength += variable.length + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + variable.length;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ##File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n // config || (config = configService.get());\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || store.get('epicenter.token') || '',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: '',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {String} `folderType` One of Model|Static|Node\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, folderType, options) {\n var path = folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ##Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * ##Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: '',\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: '',\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n domain: 'forio.com',\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ##Authentication API Service\n *\n * The Authentication API Service provides methods for logging in and logging out. On login, this service creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n * auth.logout();\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n /**\n * Logs user out from specified accounts.\n * Epicenter logout is not implemented yet, added a dummy promise that gets automatically resolved.\n *\n * **Example**\n *\n * auth.logout();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ##State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ##World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get('epicenter.project.token') || '',\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n $.extend(params, _pick(serviceOptions, ['account', 'project', 'group']));\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ##User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ##Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: '',\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar keyNames = require('../managers/key-names');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n var session = JSON.parse(store.get(keyNames.EPI_SESSION_KEY) || '{}');\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: store.get(keyNames.EPI_COOKIE_KEY) || '',\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: session.userId,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n var serviceOptions = $.extend(true, {}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.forio.com'\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n\n document.cookie = encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookieReg = new RegExp('(?:(?:^|.*;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$');\n var val = document.cookie.replace(cookieReg, '$1');\n val = decodeURIComponent(val) || null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n\n document.cookie = encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var aKeys = document.cookie.replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* ####Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar ConfigService = require('../service/configuration-service');\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar StorageFactory = require('../store/store-factory');\nvar Buffer = require('buffer').Buffer;\nvar keyNames = require('./key-names');\n\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY;\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar token;\nvar session;\n\nfunction saveSession(userInfo, store) {\n var serialized = JSON.stringify(userInfo);\n store.set(EPI_SESSION_KEY, serialized);\n\n //jshint camelcase: false\n //jscs:disable\n store.set(EPI_COOKIE_KEY, userInfo.auth_token);\n}\n\nfunction getSession(store) {\n var session = store.get(EPI_SESSION_KEY) || '{}';\n return JSON.parse(session);\n}\n\nfunction AuthManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n var urlConfig = new ConfigService(this.options).get('server');\n this.isLocal = urlConfig.isLocalhost();\n\n if (!this.options.account) {\n this.options.account = urlConfig.accountPath;\n }\n\n // null might specified to disable project filtering\n if (this.options.project === undefined) {\n this.options.project = urlConfig.projectPath;\n }\n\n this.store = new StorageFactory(this.options.store);\n session = getSession(this.store);\n token = this.store.get(EPI_COOKIE_KEY) || '';\n //jshint camelcase: false\n //jscs:disable\n this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token });\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(memberInfo, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n var groupSelection = group.groupId;\n data.groupSelection[adapterOptions.project] = groupSelection;\n var sessionInfoWithGroup = $.extend({}, sessionInfo, {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n });\n saveSession(sessionInfoWithGroup, _this.store);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n }).fail($d.reject);\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var _this = this;\n var adapterOptions = $.extend(true, { token: token }, this.options, options);\n\n var removeCookieFn = function (response) {\n _this.store.remove(EPI_COOKIE_KEY, adapterOptions);\n _this.store.remove(EPI_SESSION_KEY, adapterOptions);\n token = '';\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = $.extend(true, this.options, options);\n\n var $d = $.Deferred();\n if (token) {\n $d.resolve(token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = $.extend(true, { success: $.noop }, this.options, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return getSession(this.store, options);\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `server` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `server.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `server.project` Epicenter project id.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\n\nvar AuthManager = require('./auth-manager');\n\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n var userInfo = session.getCurrentUserSessionInfo();\n\n var defaults = {\n account: userInfo.account,\n project: userInfo.project,\n };\n var defaultCometOptions = $.extend(true, {}, defaults, userInfo, options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getDataChannel('survey-responses');\n * gc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionStore = require('../../store/store-factory');\nvar classFrom = require('../../util/inherit');\nvar UrlService = require('../../service/url-config-service');\nvar AuthManager = require('../auth-manager');\n\nvar sessionStore = new SessionStore({});\nvar urlService = new UrlService();\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, path) {\n if (!path) {\n if (!urlService.isLocalhost()) {\n path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/');\n // make sure we don't get consecuteive '/' so we have a valid path for the session\n path = path.replace(/\\/{2,}/g,'/');\n } else {\n path = '';\n }\n }\n // set the seesionKey for the run\n sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path });\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.options.path);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession);\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","'use strict';\n\nmodule.exports = {\n EPI_COOKIE_KEY: 'epicenter.project.token',\n EPI_SESSION_KEY: 'epicenter.user.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","'use strict';\n\nvar Channel = require('../service/channel-service');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n }\n };\n var defaultCometOptions = $.extend(true, {}, defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake();\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('is-array')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\nBuffer.poolSize = 8192 // not used by this implementation\n\nvar rootParent = {}\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property\n * on objects.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\nfunction typedArraySupport () {\n function Bar () {}\n try {\n var arr = new Uint8Array(1)\n arr.foo = function () { return 42 }\n arr.constructor = Bar\n return arr.foo() === 42 && // typed array instances can be augmented\n arr.constructor === Bar && // constructor can be set\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\n/**\n * Class: Buffer\n * =============\n *\n * The Buffer constructor returns instances of `Uint8Array` that are augmented\n * with function properties for all the node `Buffer` API functions. We use\n * `Uint8Array` so that square bracket notation works as expected -- it returns\n * a single octet.\n *\n * By augmenting the instances, we can avoid modifying the `Uint8Array`\n * prototype.\n */\nfunction Buffer (arg) {\n if (!(this instanceof Buffer)) {\n // Avoid going through an ArgumentsAdaptorTrampoline in the common case.\n if (arguments.length > 1) return new Buffer(arg, arguments[1])\n return new Buffer(arg)\n }\n\n this.length = 0\n this.parent = undefined\n\n // Common case.\n if (typeof arg === 'number') {\n return fromNumber(this, arg)\n }\n\n // Slightly less common case.\n if (typeof arg === 'string') {\n return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')\n }\n\n // Unusual.\n return fromObject(this, arg)\n}\n\nfunction fromNumber (that, length) {\n that = allocate(that, length < 0 ? 0 : checked(length) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < length; i++) {\n that[i] = 0\n }\n }\n return that\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'\n\n // Assumption: byteLength() return value is always < kMaxLength.\n var length = byteLength(string, encoding) | 0\n that = allocate(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromObject (that, object) {\n if (Buffer.isBuffer(object)) return fromBuffer(that, object)\n\n if (isArray(object)) return fromArray(that, object)\n\n if (object == null) {\n throw new TypeError('must start with number, buffer, array or string')\n }\n\n if (typeof ArrayBuffer !== 'undefined') {\n if (object.buffer instanceof ArrayBuffer) {\n return fromTypedArray(that, object)\n }\n if (object instanceof ArrayBuffer) {\n return fromArrayBuffer(that, object)\n }\n }\n\n if (object.length) return fromArrayLike(that, object)\n\n return fromJsonObject(that, object)\n}\n\nfunction fromBuffer (that, buffer) {\n var length = checked(buffer.length) | 0\n that = allocate(that, length)\n buffer.copy(that, 0, 0, length)\n return that\n}\n\nfunction fromArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Duplicate of fromArray() to keep fromArray() monomorphic.\nfunction fromTypedArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n // Truncating the elements is probably not what people expect from typed\n // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior\n // of the old Buffer constructor.\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n array.byteLength\n that = Buffer._augment(new Uint8Array(array))\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromTypedArray(that, new Uint8Array(array))\n }\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.\n// Returns a zero-length buffer for inputs that don't conform to the spec.\nfunction fromJsonObject (that, object) {\n var array\n var length = 0\n\n if (object.type === 'Buffer' && isArray(object.data)) {\n array = object.data\n length = checked(array.length) | 0\n }\n that = allocate(that, length)\n\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n}\n\nfunction allocate (that, length) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = Buffer._augment(new Uint8Array(length))\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that.length = length\n that._isBuffer = true\n }\n\n var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1\n if (fromPool) that.parent = rootParent\n\n return that\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (subject, encoding) {\n if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)\n\n var buf = new Buffer(subject, encoding)\n delete buf.parent\n return buf\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n var i = 0\n var len = Math.min(x, y)\n while (i < len) {\n if (a[i] !== b[i]) break\n\n ++i\n }\n\n if (i !== len) {\n x = a[i]\n y = b[i]\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')\n\n if (list.length === 0) {\n return new Buffer(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; i++) {\n length += list[i].length\n }\n }\n\n var buf = new Buffer(length)\n var pos = 0\n for (i = 0; i < list.length; i++) {\n var item = list[i]\n item.copy(buf, pos)\n pos += item.length\n }\n return buf\n}\n\nfunction byteLength (string, encoding) {\n if (typeof string !== 'string') string = '' + string\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n // Deprecated\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\n// pre-set for values that may exist in the future\nBuffer.prototype.length = undefined\nBuffer.prototype.parent = undefined\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n start = start | 0\n end = end === undefined || end === Infinity ? this.length : end | 0\n\n if (!encoding) encoding = 'utf8'\n if (start < 0) start = 0\n if (end > this.length) end = this.length\n if (end <= start) return ''\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return 0\n return Buffer.compare(this, b)\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset) {\n if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff\n else if (byteOffset < -0x80000000) byteOffset = -0x80000000\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n if (val.length === 0) return -1 // special case: looking for empty string always fails\n return String.prototype.indexOf.call(this, val, byteOffset)\n }\n if (Buffer.isBuffer(val)) {\n return arrayIndexOf(this, val, byteOffset)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset)\n }\n\n function arrayIndexOf (arr, val, byteOffset) {\n var foundIndex = -1\n for (var i = 0; byteOffset + i < arr.length; i++) {\n if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex\n } else {\n foundIndex = -1\n }\n }\n return -1\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\n// `get` is deprecated\nBuffer.prototype.get = function get (offset) {\n console.log('.get() is deprecated. Access using array indexes instead.')\n return this.readUInt8(offset)\n}\n\n// `set` is deprecated\nBuffer.prototype.set = function set (v, offset) {\n console.log('.set() is deprecated. Access using array indexes instead.')\n return this.writeUInt8(v, offset)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; i++) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) throw new Error('Invalid hex string')\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n var swap = encoding\n encoding = offset\n offset = length | 0\n length = swap\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; i++) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; i++) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = Buffer._augment(this.subarray(start, end))\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; i++) {\n newBuf[i] = this[i + start]\n }\n }\n\n if (newBuf.length) newBuf.parent = this.parent || this\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = value < 0 ? 1 : 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (value > max || value < min) throw new RangeError('value is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('index out of range')\n if (offset < 0) throw new RangeError('index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; i--) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; i++) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n target._set(this.subarray(start, start + len), targetStart)\n }\n\n return len\n}\n\n// fill(value, start=0, end=buffer.length)\nBuffer.prototype.fill = function fill (value, start, end) {\n if (!value) value = 0\n if (!start) start = 0\n if (!end) end = this.length\n\n if (end < start) throw new RangeError('end < start')\n\n // Fill 0 bytes; we're done\n if (end === start) return\n if (this.length === 0) return\n\n if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')\n if (end < 0 || end > this.length) throw new RangeError('end out of bounds')\n\n var i\n if (typeof value === 'number') {\n for (i = start; i < end; i++) {\n this[i] = value\n }\n } else {\n var bytes = utf8ToBytes(value.toString())\n var len = bytes.length\n for (i = start; i < end; i++) {\n this[i] = bytes[i % len]\n }\n }\n\n return this\n}\n\n/**\n * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.\n * Added in Node 0.12. Only available in browsers that support ArrayBuffer.\n */\nBuffer.prototype.toArrayBuffer = function toArrayBuffer () {\n if (typeof Uint8Array !== 'undefined') {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n return (new Buffer(this)).buffer\n } else {\n var buf = new Uint8Array(this.length)\n for (var i = 0, len = buf.length; i < len; i += 1) {\n buf[i] = this[i]\n }\n return buf.buffer\n }\n } else {\n throw new TypeError('Buffer.toArrayBuffer not supported in this browser')\n }\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar BP = Buffer.prototype\n\n/**\n * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods\n */\nBuffer._augment = function _augment (arr) {\n arr.constructor = Buffer\n arr._isBuffer = true\n\n // save reference to original Uint8Array set method before overwriting\n arr._set = arr.set\n\n // deprecated\n arr.get = BP.get\n arr.set = BP.set\n\n arr.write = BP.write\n arr.toString = BP.toString\n arr.toLocaleString = BP.toString\n arr.toJSON = BP.toJSON\n arr.equals = BP.equals\n arr.compare = BP.compare\n arr.indexOf = BP.indexOf\n arr.copy = BP.copy\n arr.slice = BP.slice\n arr.readUIntLE = BP.readUIntLE\n arr.readUIntBE = BP.readUIntBE\n arr.readUInt8 = BP.readUInt8\n arr.readUInt16LE = BP.readUInt16LE\n arr.readUInt16BE = BP.readUInt16BE\n arr.readUInt32LE = BP.readUInt32LE\n arr.readUInt32BE = BP.readUInt32BE\n arr.readIntLE = BP.readIntLE\n arr.readIntBE = BP.readIntBE\n arr.readInt8 = BP.readInt8\n arr.readInt16LE = BP.readInt16LE\n arr.readInt16BE = BP.readInt16BE\n arr.readInt32LE = BP.readInt32LE\n arr.readInt32BE = BP.readInt32BE\n arr.readFloatLE = BP.readFloatLE\n arr.readFloatBE = BP.readFloatBE\n arr.readDoubleLE = BP.readDoubleLE\n arr.readDoubleBE = BP.readDoubleBE\n arr.writeUInt8 = BP.writeUInt8\n arr.writeUIntLE = BP.writeUIntLE\n arr.writeUIntBE = BP.writeUIntBE\n arr.writeUInt16LE = BP.writeUInt16LE\n arr.writeUInt16BE = BP.writeUInt16BE\n arr.writeUInt32LE = BP.writeUInt32LE\n arr.writeUInt32BE = BP.writeUInt32BE\n arr.writeIntLE = BP.writeIntLE\n arr.writeIntBE = BP.writeIntBE\n arr.writeInt8 = BP.writeInt8\n arr.writeInt16LE = BP.writeInt16LE\n arr.writeInt16BE = BP.writeInt16BE\n arr.writeInt32LE = BP.writeInt32LE\n arr.writeInt32BE = BP.writeInt32BE\n arr.writeFloatLE = BP.writeFloatLE\n arr.writeFloatBE = BP.writeFloatBE\n arr.writeDoubleLE = BP.writeDoubleLE\n arr.writeDoubleBE = BP.writeDoubleBE\n arr.fill = BP.fill\n arr.inspect = BP.inspect\n arr.toArrayBuffer = BP.toArrayBuffer\n\n return arr\n}\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; i++) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; i++) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; i++) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n;(function (exports) {\n\t'use strict';\n\n var Arr = (typeof Uint8Array !== 'undefined')\n ? Uint8Array\n : Array\n\n\tvar PLUS = '+'.charCodeAt(0)\n\tvar SLASH = '/'.charCodeAt(0)\n\tvar NUMBER = '0'.charCodeAt(0)\n\tvar LOWER = 'a'.charCodeAt(0)\n\tvar UPPER = 'A'.charCodeAt(0)\n\tvar PLUS_URL_SAFE = '-'.charCodeAt(0)\n\tvar SLASH_URL_SAFE = '_'.charCodeAt(0)\n\n\tfunction decode (elt) {\n\t\tvar code = elt.charCodeAt(0)\n\t\tif (code === PLUS ||\n\t\t code === PLUS_URL_SAFE)\n\t\t\treturn 62 // '+'\n\t\tif (code === SLASH ||\n\t\t code === SLASH_URL_SAFE)\n\t\t\treturn 63 // '/'\n\t\tif (code < NUMBER)\n\t\t\treturn -1 //no match\n\t\tif (code < NUMBER + 10)\n\t\t\treturn code - NUMBER + 26 + 26\n\t\tif (code < UPPER + 26)\n\t\t\treturn code - UPPER\n\t\tif (code < LOWER + 26)\n\t\t\treturn code - LOWER + 26\n\t}\n\n\tfunction b64ToByteArray (b64) {\n\t\tvar i, j, l, tmp, placeHolders, arr\n\n\t\tif (b64.length % 4 > 0) {\n\t\t\tthrow new Error('Invalid string. Length must be a multiple of 4')\n\t\t}\n\n\t\t// the number of equal signs (place holders)\n\t\t// if there are two placeholders, than the two characters before it\n\t\t// represent one byte\n\t\t// if there is only one, then the three characters before it represent 2 bytes\n\t\t// this is just a cheap hack to not do indexOf twice\n\t\tvar len = b64.length\n\t\tplaceHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0\n\n\t\t// base64 is 4/3 + up to two characters of the original data\n\t\tarr = new Arr(b64.length * 3 / 4 - placeHolders)\n\n\t\t// if there are placeholders, only get up to the last complete 4 chars\n\t\tl = placeHolders > 0 ? b64.length - 4 : b64.length\n\n\t\tvar L = 0\n\n\t\tfunction push (v) {\n\t\t\tarr[L++] = v\n\t\t}\n\n\t\tfor (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))\n\t\t\tpush((tmp & 0xFF0000) >> 16)\n\t\t\tpush((tmp & 0xFF00) >> 8)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\tif (placeHolders === 2) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)\n\t\t\tpush(tmp & 0xFF)\n\t\t} else if (placeHolders === 1) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)\n\t\t\tpush((tmp >> 8) & 0xFF)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\treturn arr\n\t}\n\n\tfunction uint8ToBase64 (uint8) {\n\t\tvar i,\n\t\t\textraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes\n\t\t\toutput = \"\",\n\t\t\ttemp, length\n\n\t\tfunction encode (num) {\n\t\t\treturn lookup.charAt(num)\n\t\t}\n\n\t\tfunction tripletToBase64 (num) {\n\t\t\treturn encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)\n\t\t}\n\n\t\t// go through the array every three bytes, we'll deal with trailing stuff later\n\t\tfor (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n\t\t\ttemp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n\t\t\toutput += tripletToBase64(temp)\n\t\t}\n\n\t\t// pad the end with zeros, but make sure to not forget the extra bytes\n\t\tswitch (extraBytes) {\n\t\t\tcase 1:\n\t\t\t\ttemp = uint8[uint8.length - 1]\n\t\t\t\toutput += encode(temp >> 2)\n\t\t\t\toutput += encode((temp << 4) & 0x3F)\n\t\t\t\toutput += '=='\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\ttemp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])\n\t\t\t\toutput += encode(temp >> 10)\n\t\t\t\toutput += encode((temp >> 4) & 0x3F)\n\t\t\t\toutput += encode((temp << 2) & 0x3F)\n\t\t\t\toutput += '='\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn output\n\t}\n\n\texports.toByteArray = b64ToByteArray\n\texports.fromByteArray = uint8ToBase64\n}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))\n","\n/**\n * isArray\n */\n\nvar isArray = Array.isArray;\n\n/**\n * toString\n */\n\nvar str = Object.prototype.toString;\n\n/**\n * Whether or not the given `val`\n * is an array.\n *\n * example:\n *\n * isArray([]);\n * // > true\n * isArray(arguments);\n * // > false\n * isArray('');\n * // > false\n *\n * @param {mixed} val\n * @return {bool}\n */\n\nmodule.exports = isArray || function (val) {\n return !! val && '[object Array]' == str.call(val);\n};\n"]} \ No newline at end of file