From 4742fd7ed2f0c9063bc3d0715f08976911b048e6 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Tue, 8 Jan 2019 07:58:46 +1100 Subject: [PATCH] Initial commit of wails build --- .1.gitignore | 17 + .gitignore | 5 + a_wails-packr.go | 20 + app.go | 142 ++++ app_cli.go | 38 + app_config.go | 99 +++ binding_function.go | 160 ++++ binding_manager.go | 267 ++++++ binding_method.go | 211 +++++ cmd/bundle.go | 193 +++++ cmd/program.go | 38 +- cmd/shell.go | 27 + cmd/templates.go | 10 + cmd/wails/3_build.go | 225 +++++ event_manager.go | 148 ++++ go.mod | 9 + go.sum | 20 + ipc_call.go | 38 + ipc_event.go | 40 + ipc_log.go | 27 + ipc_manager.go | 162 ++++ ipc_message.go | 93 ++ ipc_response.go | 43 + log.go | 40 + log_custom.go | 82 ++ renderer.go | 31 + renderer_headless.go | 279 ++++++ renderer_webview.go | 383 +++++++++ runtime.go | 17 + runtime_dialog.go | 23 + runtime_events.go | 21 + runtime_log.go | 12 + runtime_window.go | 32 + utils.go | 12 + webview/webview.go | 372 ++++++++ webview/webview.h | 1927 ++++++++++++++++++++++++++++++++++++++++++ 36 files changed, 5261 insertions(+), 2 deletions(-) create mode 100644 .1.gitignore create mode 100644 a_wails-packr.go create mode 100644 app.go create mode 100644 app_cli.go create mode 100644 app_config.go create mode 100644 binding_function.go create mode 100644 binding_manager.go create mode 100644 binding_method.go create mode 100644 cmd/bundle.go create mode 100644 cmd/shell.go create mode 100644 cmd/wails/3_build.go create mode 100644 event_manager.go create mode 100644 ipc_call.go create mode 100644 ipc_event.go create mode 100644 ipc_log.go create mode 100644 ipc_manager.go create mode 100644 ipc_message.go create mode 100644 ipc_response.go create mode 100644 log.go create mode 100644 log_custom.go create mode 100644 renderer.go create mode 100644 renderer_headless.go create mode 100644 renderer_webview.go create mode 100644 runtime.go create mode 100644 runtime_dialog.go create mode 100644 runtime_events.go create mode 100644 runtime_log.go create mode 100644 runtime_window.go create mode 100644 utils.go create mode 100644 webview/webview.go create mode 100644 webview/webview.h diff --git a/.1.gitignore b/.1.gitignore new file mode 100644 index 000000000..2074be896 --- /dev/null +++ b/.1.gitignore @@ -0,0 +1,17 @@ +lib/project/templates/vue +lib/project/templates/blank +tools +test +.vscode/ +tmp +examples/**/example* +!examples/**/*.* +node_modules +cmd.old +lib.old +cmd/wails/wails +.DS_Store +rewrite +.rewrite +examples/WIP/* +docs \ No newline at end of file diff --git a/.gitignore b/.gitignore index f1c181ec9..76782fa86 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,8 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out + +examples/**/example* +!examples/**/*.* +cmd/wails/wails +.DS_Store \ No newline at end of file diff --git a/a_wails-packr.go b/a_wails-packr.go new file mode 100644 index 000000000..646cd8cbc --- /dev/null +++ b/a_wails-packr.go @@ -0,0 +1,20 @@ +// Code generated by github.com/gobuffalo/packr. DO NOT EDIT. + +package wails + +import "github.com/gobuffalo/packr" + +// You can use the "packr clean" command to clean up this, +// and any other packr generated files. +func init() { + packr.PackJSONBytes("./assets/default", "default.html", "\"PGRpdiBpZD0iYXBwIj48L2Rpdj4=\"") + packr.PackJSONBytes("./assets/default", "jquery.3.3.1.min.js", "\"LyohIGpRdWVyeSB2My4zLjEgLWFqYXgsLWFqYXgvanNvbnAsLWFqYXgvbG9hZCwtYWpheC9wYXJzZVhNTCwtYWpheC9zY3JpcHQsLWFqYXgvdmFyL2xvY2F0aW9uLC1hamF4L3Zhci9ub25jZSwtYWpheC92YXIvcnF1ZXJ5LC1hamF4L3hociwtbWFuaXB1bGF0aW9uL19ldmFsVXJsLC1ldmVudC9hamF4LC1lZmZlY3RzLC1lZmZlY3RzL1R3ZWVuLC1lZmZlY3RzL2FuaW1hdGVkU2VsZWN0b3IgfCAoYykgSlMgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzIHwganF1ZXJ5Lm9yZy9saWNlbnNlICovCiFmdW5jdGlvbiAoZSwgdCkgeyAidXNlIHN0cmljdCI7ICJvYmplY3QiID09IHR5cGVvZiBtb2R1bGUgJiYgIm9iamVjdCIgPT0gdHlwZW9mIG1vZHVsZS5leHBvcnRzID8gbW9kdWxlLmV4cG9ydHMgPSBlLmRvY3VtZW50ID8gdChlLCAhMCkgOiBmdW5jdGlvbiAoZSkgeyBpZiAoIWUuZG9jdW1lbnQpIHRocm93IG5ldyBFcnJvcigialF1ZXJ5IHJlcXVpcmVzIGEgd2luZG93IHdpdGggYSBkb2N1bWVudCIpOyByZXR1cm4gdChlKSB9IDogdChlKSB9KCJ1bmRlZmluZWQiICE9IHR5cGVvZiB3aW5kb3cgPyB3aW5kb3cgOiB0aGlzLCBmdW5jdGlvbiAoZSwgdCkgeyAidXNlIHN0cmljdCI7IHZhciBuID0gW10sIHIgPSBlLmRvY3VtZW50LCBpID0gT2JqZWN0LmdldFByb3RvdHlwZU9mLCBvID0gbi5zbGljZSwgYSA9IG4uY29uY2F0LCB1ID0gbi5wdXNoLCBzID0gbi5pbmRleE9mLCBsID0ge30sIGMgPSBsLnRvU3RyaW5nLCBmID0gbC5oYXNPd25Qcm9wZXJ0eSwgZCA9IGYudG9TdHJpbmcsIHAgPSBkLmNhbGwoT2JqZWN0KSwgaCA9IHt9LCBnID0gZnVuY3Rpb24gZSh0KSB7IHJldHVybiAiZnVuY3Rpb24iID09IHR5cGVvZiB0ICYmICJudW1iZXIiICE9IHR5cGVvZiB0Lm5vZGVUeXBlIH0sIHYgPSBmdW5jdGlvbiBlKHQpIHsgcmV0dXJuIG51bGwgIT0gdCAmJiB0ID09PSB0LndpbmRvdyB9LCB5ID0geyB0eXBlOiAhMCwgc3JjOiAhMCwgbm9Nb2R1bGU6ICEwIH07IGZ1bmN0aW9uIG0oZSwgdCwgbikgeyB2YXIgaSwgbyA9ICh0ID0gdCB8fCByKS5jcmVhdGVFbGVtZW50KCJzY3JpcHQiKTsgaWYgKG8udGV4dCA9IGUsIG4pIGZvciAoaSBpbiB5KSBuW2ldICYmIChvW2ldID0gbltpXSk7IHQuaGVhZC5hcHBlbmRDaGlsZChvKS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKG8pIH0gZnVuY3Rpb24gYihlKSB7IHJldHVybiBudWxsID09IGUgPyBlICsgIiIgOiAib2JqZWN0IiA9PSB0eXBlb2YgZSB8fCAiZnVuY3Rpb24iID09IHR5cGVvZiBlID8gbFtjLmNhbGwoZSldIHx8ICJvYmplY3QiIDogdHlwZW9mIGUgfSB2YXIgeCA9ICIzLjMuMSAtYWpheCwtYWpheC9qc29ucCwtYWpheC9sb2FkLC1hamF4L3BhcnNlWE1MLC1hamF4L3NjcmlwdCwtYWpheC92YXIvbG9jYXRpb24sLWFqYXgvdmFyL25vbmNlLC1hamF4L3Zhci9ycXVlcnksLWFqYXgveGhyLC1tYW5pcHVsYXRpb24vX2V2YWxVcmwsLWV2ZW50L2FqYXgsLWVmZmVjdHMsLWVmZmVjdHMvVHdlZW4sLWVmZmVjdHMvYW5pbWF0ZWRTZWxlY3RvciIsIHcgPSBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gbmV3IHcuZm4uaW5pdChlLCB0KSB9LCBDID0gL15bXHNcdUZFRkZceEEwXSt8W1xzXHVGRUZGXHhBMF0rJC9nOyB3LmZuID0gdy5wcm90b3R5cGUgPSB7IGpxdWVyeTogeCwgY29uc3RydWN0b3I6IHcsIGxlbmd0aDogMCwgdG9BcnJheTogZnVuY3Rpb24gKCkgeyByZXR1cm4gby5jYWxsKHRoaXMpIH0sIGdldDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIG51bGwgPT0gZSA/IG8uY2FsbCh0aGlzKSA6IGUgPCAwID8gdGhpc1tlICsgdGhpcy5sZW5ndGhdIDogdGhpc1tlXSB9LCBwdXNoU3RhY2s6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gdy5tZXJnZSh0aGlzLmNvbnN0cnVjdG9yKCksIGUpOyByZXR1cm4gdC5wcmV2T2JqZWN0ID0gdGhpcywgdCB9LCBlYWNoOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdy5lYWNoKHRoaXMsIGUpIH0sIG1hcDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHRoaXMucHVzaFN0YWNrKHcubWFwKHRoaXMsIGZ1bmN0aW9uICh0LCBuKSB7IHJldHVybiBlLmNhbGwodCwgbiwgdCkgfSkpIH0sIHNsaWNlOiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLnB1c2hTdGFjayhvLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykpIH0sIGZpcnN0OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLmVxKDApIH0sIGxhc3Q6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMuZXEoLTEpIH0sIGVxOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IHRoaXMubGVuZ3RoLCBuID0gK2UgKyAoZSA8IDAgPyB0IDogMCk7IHJldHVybiB0aGlzLnB1c2hTdGFjayhuID49IDAgJiYgbiA8IHQgPyBbdGhpc1tuXV0gOiBbXSkgfSwgZW5kOiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLnByZXZPYmplY3QgfHwgdGhpcy5jb25zdHJ1Y3RvcigpIH0sIHB1c2g6IHUsIHNvcnQ6IG4uc29ydCwgc3BsaWNlOiBuLnNwbGljZSB9LCB3LmV4dGVuZCA9IHcuZm4uZXh0ZW5kID0gZnVuY3Rpb24gKCkgeyB2YXIgZSwgdCwgbiwgciwgaSwgbywgYSA9IGFyZ3VtZW50c1swXSB8fCB7fSwgdSA9IDEsIHMgPSBhcmd1bWVudHMubGVuZ3RoLCBsID0gITE7IGZvciAoImJvb2xlYW4iID09IHR5cGVvZiBhICYmIChsID0gYSwgYSA9IGFyZ3VtZW50c1t1XSB8fCB7fSwgdSsrKSwgIm9iamVjdCIgPT0gdHlwZW9mIGEgfHwgZyhhKSB8fCAoYSA9IHt9KSwgdSA9PT0gcyAmJiAoYSA9IHRoaXMsIHUtLSk7IHUgPCBzOyB1KyspaWYgKG51bGwgIT0gKGUgPSBhcmd1bWVudHNbdV0pKSBmb3IgKHQgaW4gZSkgbiA9IGFbdF0sIGEgIT09IChyID0gZVt0XSkgJiYgKGwgJiYgciAmJiAody5pc1BsYWluT2JqZWN0KHIpIHx8IChpID0gQXJyYXkuaXNBcnJheShyKSkpID8gKGkgPyAoaSA9ICExLCBvID0gbiAmJiBBcnJheS5pc0FycmF5KG4pID8gbiA6IFtdKSA6IG8gPSBuICYmIHcuaXNQbGFpbk9iamVjdChuKSA/IG4gOiB7fSwgYVt0XSA9IHcuZXh0ZW5kKGwsIG8sIHIpKSA6IHZvaWQgMCAhPT0gciAmJiAoYVt0XSA9IHIpKTsgcmV0dXJuIGEgfSwgdy5leHRlbmQoeyBleHBhbmRvOiAialF1ZXJ5IiArICh4ICsgTWF0aC5yYW5kb20oKSkucmVwbGFjZSgvXEQvZywgIiIpLCBpc1JlYWR5OiAhMCwgZXJyb3I6IGZ1bmN0aW9uIChlKSB7IHRocm93IG5ldyBFcnJvcihlKSB9LCBub29wOiBmdW5jdGlvbiAoKSB7IH0sIGlzUGxhaW5PYmplY3Q6IGZ1bmN0aW9uIChlKSB7IHZhciB0LCBuOyByZXR1cm4gISghZSB8fCAiW29iamVjdCBPYmplY3RdIiAhPT0gYy5jYWxsKGUpKSAmJiAoISh0ID0gaShlKSkgfHwgImZ1bmN0aW9uIiA9PSB0eXBlb2YgKG4gPSBmLmNhbGwodCwgImNvbnN0cnVjdG9yIikgJiYgdC5jb25zdHJ1Y3RvcikgJiYgZC5jYWxsKG4pID09PSBwKSB9LCBpc0VtcHR5T2JqZWN0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdDsgZm9yICh0IGluIGUpIHJldHVybiAhMTsgcmV0dXJuICEwIH0sIGdsb2JhbEV2YWw6IGZ1bmN0aW9uIChlKSB7IG0oZSkgfSwgZWFjaDogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIgPSAwOyBpZiAoVChlKSkgeyBmb3IgKG4gPSBlLmxlbmd0aDsgciA8IG47IHIrKylpZiAoITEgPT09IHQuY2FsbChlW3JdLCByLCBlW3JdKSkgYnJlYWsgfSBlbHNlIGZvciAociBpbiBlKSBpZiAoITEgPT09IHQuY2FsbChlW3JdLCByLCBlW3JdKSkgYnJlYWs7IHJldHVybiBlIH0sIHRyaW06IGZ1bmN0aW9uIChlKSB7IHJldHVybiBudWxsID09IGUgPyAiIiA6IChlICsgIiIpLnJlcGxhY2UoQywgIiIpIH0sIG1ha2VBcnJheTogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4gPSB0IHx8IFtdOyByZXR1cm4gbnVsbCAhPSBlICYmIChUKE9iamVjdChlKSkgPyB3Lm1lcmdlKG4sICJzdHJpbmciID09IHR5cGVvZiBlID8gW2VdIDogZSkgOiB1LmNhbGwobiwgZSkpLCBuIH0sIGluQXJyYXk6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBudWxsID09IHQgPyAtMSA6IHMuY2FsbCh0LCBlLCBuKSB9LCBtZXJnZTogZnVuY3Rpb24gKGUsIHQpIHsgZm9yICh2YXIgbiA9ICt0Lmxlbmd0aCwgciA9IDAsIGkgPSBlLmxlbmd0aDsgciA8IG47IHIrKyllW2krK10gPSB0W3JdOyByZXR1cm4gZS5sZW5ndGggPSBpLCBlIH0sIGdyZXA6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IGZvciAodmFyIHIsIGkgPSBbXSwgbyA9IDAsIGEgPSBlLmxlbmd0aCwgdSA9ICFuOyBvIDwgYTsgbysrKShyID0gIXQoZVtvXSwgbykpICE9PSB1ICYmIGkucHVzaChlW29dKTsgcmV0dXJuIGkgfSwgbWFwOiBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciwgaSwgbyA9IDAsIHUgPSBbXTsgaWYgKFQoZSkpIGZvciAociA9IGUubGVuZ3RoOyBvIDwgcjsgbysrKW51bGwgIT0gKGkgPSB0KGVbb10sIG8sIG4pKSAmJiB1LnB1c2goaSk7IGVsc2UgZm9yIChvIGluIGUpIG51bGwgIT0gKGkgPSB0KGVbb10sIG8sIG4pKSAmJiB1LnB1c2goaSk7IHJldHVybiBhLmFwcGx5KFtdLCB1KSB9LCBndWlkOiAxLCBzdXBwb3J0OiBoIH0pLCAiZnVuY3Rpb24iID09IHR5cGVvZiBTeW1ib2wgJiYgKHcuZm5bU3ltYm9sLml0ZXJhdG9yXSA9IG5bU3ltYm9sLml0ZXJhdG9yXSksIHcuZWFjaCgiQm9vbGVhbiBOdW1iZXIgU3RyaW5nIEZ1bmN0aW9uIEFycmF5IERhdGUgUmVnRXhwIE9iamVjdCBFcnJvciBTeW1ib2wiLnNwbGl0KCIgIiksIGZ1bmN0aW9uIChlLCB0KSB7IGxbIltvYmplY3QgIiArIHQgKyAiXSJdID0gdC50b0xvd2VyQ2FzZSgpIH0pOyBmdW5jdGlvbiBUKGUpIHsgdmFyIHQgPSAhIWUgJiYgImxlbmd0aCIgaW4gZSAmJiBlLmxlbmd0aCwgbiA9IGIoZSk7IHJldHVybiAhZyhlKSAmJiAhdihlKSAmJiAoImFycmF5IiA9PT0gbiB8fCAwID09PSB0IHx8ICJudW1iZXIiID09IHR5cGVvZiB0ICYmIHQgPiAwICYmIHQgLSAxIGluIGUpIH0gdmFyIEUgPSBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgbiwgciwgaSwgbywgYSwgdSwgcywgbCwgYywgZiwgZCwgcCwgaCwgZywgdiwgeSwgbSwgYiwgeCA9ICJzaXp6bGUiICsgMSAqIG5ldyBEYXRlLCB3ID0gZS5kb2N1bWVudCwgQyA9IDAsIFQgPSAwLCBFID0gYWUoKSwgTiA9IGFlKCksIGsgPSBhZSgpLCBBID0gZnVuY3Rpb24gKGUsIHQpIHsgcmV0dXJuIGUgPT09IHQgJiYgKGYgPSAhMCksIDAgfSwgRCA9IHt9Lmhhc093blByb3BlcnR5LCBTID0gW10sIEwgPSBTLnBvcCwgaiA9IFMucHVzaCwgcSA9IFMucHVzaCwgTyA9IFMuc2xpY2UsIFAgPSBmdW5jdGlvbiAoZSwgdCkgeyBmb3IgKHZhciBuID0gMCwgciA9IGUubGVuZ3RoOyBuIDwgcjsgbisrKWlmIChlW25dID09PSB0KSByZXR1cm4gbjsgcmV0dXJuIC0xIH0sIEggPSAiY2hlY2tlZHxzZWxlY3RlZHxhc3luY3xhdXRvZm9jdXN8YXV0b3BsYXl8Y29udHJvbHN8ZGVmZXJ8ZGlzYWJsZWR8aGlkZGVufGlzbWFwfGxvb3B8bXVsdGlwbGV8b3BlbnxyZWFkb25seXxyZXF1aXJlZHxzY29wZWQiLCBJID0gIltcXHgyMFxcdFxcclxcblxcZl0iLCBSID0gIig/OlxcXFwufFtcXHctXXxbXlwwLVxceGEwXSkrIiwgQiA9ICJcXFsiICsgSSArICIqKCIgKyBSICsgIikoPzoiICsgSSArICIqKFsqXiR8IX5dPz0pIiArIEkgKyAiKig/OicoKD86XFxcXC58W15cXFxcJ10pKiknfFwiKCg/OlxcXFwufFteXFxcXFwiXSkqKVwifCgiICsgUiArICIpKXwpIiArIEkgKyAiKlxcXSIsIE0gPSAiOigiICsgUiArICIpKD86XFwoKCgnKCg/OlxcXFwufFteXFxcXCddKSopJ3xcIigoPzpcXFxcLnxbXlxcXFxcIl0pKilcIil8KCg/OlxcXFwufFteXFxcXCgpW1xcXV18IiArIEIgKyAiKSopfC4qKVxcKXwpIiwgVyA9IG5ldyBSZWdFeHAoSSArICIrIiwgImciKSwgJCA9IG5ldyBSZWdFeHAoIl4iICsgSSArICIrfCgoPzpefFteXFxcXF0pKD86XFxcXC4pKikiICsgSSArICIrJCIsICJnIiksIEYgPSBuZXcgUmVnRXhwKCJeIiArIEkgKyAiKiwiICsgSSArICIqIiksIHogPSBuZXcgUmVnRXhwKCJeIiArIEkgKyAiKihbPit+XXwiICsgSSArICIpIiArIEkgKyAiKiIpLCBfID0gbmV3IFJlZ0V4cCgiPSIgKyBJICsgIiooW15cXF0nXCJdKj8pIiArIEkgKyAiKlxcXSIsICJnIiksIFUgPSBuZXcgUmVnRXhwKE0pLCBWID0gbmV3IFJlZ0V4cCgiXiIgKyBSICsgIiQiKSwgWCA9IHsgSUQ6IG5ldyBSZWdFeHAoIl4jKCIgKyBSICsgIikiKSwgQ0xBU1M6IG5ldyBSZWdFeHAoIl5cXC4oIiArIFIgKyAiKSIpLCBUQUc6IG5ldyBSZWdFeHAoIl4oIiArIFIgKyAifFsqXSkiKSwgQVRUUjogbmV3IFJlZ0V4cCgiXiIgKyBCKSwgUFNFVURPOiBuZXcgUmVnRXhwKCJeIiArIE0pLCBDSElMRDogbmV3IFJlZ0V4cCgiXjoob25seXxmaXJzdHxsYXN0fG50aHxudGgtbGFzdCktKGNoaWxkfG9mLXR5cGUpKD86XFwoIiArIEkgKyAiKihldmVufG9kZHwoKFsrLV18KShcXGQqKW58KSIgKyBJICsgIiooPzooWystXXwpIiArIEkgKyAiKihcXGQrKXwpKSIgKyBJICsgIipcXCl8KSIsICJpIiksIGJvb2w6IG5ldyBSZWdFeHAoIl4oPzoiICsgSCArICIpJCIsICJpIiksIG5lZWRzQ29udGV4dDogbmV3IFJlZ0V4cCgiXiIgKyBJICsgIipbPit+XXw6KGV2ZW58b2RkfGVxfGd0fGx0fG50aHxmaXJzdHxsYXN0KSg/OlxcKCIgKyBJICsgIiooKD86LVxcZCk/XFxkKikiICsgSSArICIqXFwpfCkoPz1bXi1dfCQpIiwgImkiKSB9LCBRID0gL14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWF8YnV0dG9uKSQvaSwgWSA9IC9eaFxkJC9pLCBHID0gL15bXntdK1x7XHMqXFtuYXRpdmUgXHcvLCBLID0gL14oPzojKFtcdy1dKyl8KFx3Kyl8XC4oW1x3LV0rKSkkLywgSiA9IC9bK35dLywgWiA9IG5ldyBSZWdFeHAoIlxcXFwoW1xcZGEtZl17MSw2fSIgKyBJICsgIj98KCIgKyBJICsgIil8LikiLCAiaWciKSwgZWUgPSBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciA9ICIweCIgKyB0IC0gNjU1MzY7IHJldHVybiByICE9PSByIHx8IG4gPyB0IDogciA8IDAgPyBTdHJpbmcuZnJvbUNoYXJDb2RlKHIgKyA2NTUzNikgOiBTdHJpbmcuZnJvbUNoYXJDb2RlKHIgPj4gMTAgfCA1NTI5NiwgMTAyMyAmIHIgfCA1NjMyMCkgfSwgdGUgPSAvKFtcMC1ceDFmXHg3Zl18Xi0/XGQpfF4tJHxbXlwwLVx4MWZceDdmLVx1RkZGRlx3LV0vZywgbmUgPSBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gdCA/ICJcMCIgPT09IGUgPyAiXHVmZmZkIiA6IGUuc2xpY2UoMCwgLTEpICsgIlxcIiArIGUuY2hhckNvZGVBdChlLmxlbmd0aCAtIDEpLnRvU3RyaW5nKDE2KSArICIgIiA6ICJcXCIgKyBlIH0sIHJlID0gZnVuY3Rpb24gKCkgeyBkKCkgfSwgaWUgPSBtZShmdW5jdGlvbiAoZSkgeyByZXR1cm4gITAgPT09IGUuZGlzYWJsZWQgJiYgKCJmb3JtIiBpbiBlIHx8ICJsYWJlbCIgaW4gZSkgfSwgeyBkaXI6ICJwYXJlbnROb2RlIiwgbmV4dDogImxlZ2VuZCIgfSk7IHRyeSB7IHEuYXBwbHkoUyA9IE8uY2FsbCh3LmNoaWxkTm9kZXMpLCB3LmNoaWxkTm9kZXMpLCBTW3cuY2hpbGROb2Rlcy5sZW5ndGhdLm5vZGVUeXBlIH0gY2F0Y2ggKGUpIHsgcSA9IHsgYXBwbHk6IFMubGVuZ3RoID8gZnVuY3Rpb24gKGUsIHQpIHsgai5hcHBseShlLCBPLmNhbGwodCkpIH0gOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IGUubGVuZ3RoLCByID0gMDsgd2hpbGUgKGVbbisrXSA9IHRbcisrXSk7IGUubGVuZ3RoID0gbiAtIDEgfSB9IH0gZnVuY3Rpb24gb2UoZSwgdCwgciwgaSkgeyB2YXIgbywgdSwgbCwgYywgZiwgaCwgeSwgbSA9IHQgJiYgdC5vd25lckRvY3VtZW50LCBDID0gdCA/IHQubm9kZVR5cGUgOiA5OyBpZiAociA9IHIgfHwgW10sICJzdHJpbmciICE9IHR5cGVvZiBlIHx8ICFlIHx8IDEgIT09IEMgJiYgOSAhPT0gQyAmJiAxMSAhPT0gQykgcmV0dXJuIHI7IGlmICghaSAmJiAoKHQgPyB0Lm93bmVyRG9jdW1lbnQgfHwgdCA6IHcpICE9PSBwICYmIGQodCksIHQgPSB0IHx8IHAsIGcpKSB7IGlmICgxMSAhPT0gQyAmJiAoZiA9IEsuZXhlYyhlKSkpIGlmIChvID0gZlsxXSkgeyBpZiAoOSA9PT0gQykgeyBpZiAoIShsID0gdC5nZXRFbGVtZW50QnlJZChvKSkpIHJldHVybiByOyBpZiAobC5pZCA9PT0gbykgcmV0dXJuIHIucHVzaChsKSwgciB9IGVsc2UgaWYgKG0gJiYgKGwgPSBtLmdldEVsZW1lbnRCeUlkKG8pKSAmJiBiKHQsIGwpICYmIGwuaWQgPT09IG8pIHJldHVybiByLnB1c2gobCksIHIgfSBlbHNlIHsgaWYgKGZbMl0pIHJldHVybiBxLmFwcGx5KHIsIHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoZSkpLCByOyBpZiAoKG8gPSBmWzNdKSAmJiBuLmdldEVsZW1lbnRzQnlDbGFzc05hbWUgJiYgdC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKSByZXR1cm4gcS5hcHBseShyLCB0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUobykpLCByIH0gaWYgKG4ucXNhICYmICFrW2UgKyAiICJdICYmICghdiB8fCAhdi50ZXN0KGUpKSkgeyBpZiAoMSAhPT0gQykgbSA9IHQsIHkgPSBlOyBlbHNlIGlmICgib2JqZWN0IiAhPT0gdC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpKSB7IChjID0gdC5nZXRBdHRyaWJ1dGUoImlkIikpID8gYyA9IGMucmVwbGFjZSh0ZSwgbmUpIDogdC5zZXRBdHRyaWJ1dGUoImlkIiwgYyA9IHgpLCB1ID0gKGggPSBhKGUpKS5sZW5ndGg7IHdoaWxlICh1LS0pIGhbdV0gPSAiIyIgKyBjICsgIiAiICsgeWUoaFt1XSk7IHkgPSBoLmpvaW4oIiwiKSwgbSA9IEoudGVzdChlKSAmJiBnZSh0LnBhcmVudE5vZGUpIHx8IHQgfSBpZiAoeSkgdHJ5IHsgcmV0dXJuIHEuYXBwbHkociwgbS5xdWVyeVNlbGVjdG9yQWxsKHkpKSwgciB9IGNhdGNoIChlKSB7IH0gZmluYWxseSB7IGMgPT09IHggJiYgdC5yZW1vdmVBdHRyaWJ1dGUoImlkIikgfSB9IH0gcmV0dXJuIHMoZS5yZXBsYWNlKCQsICIkMSIpLCB0LCByLCBpKSB9IGZ1bmN0aW9uIGFlKCkgeyB2YXIgZSA9IFtdOyBmdW5jdGlvbiB0KG4sIGkpIHsgcmV0dXJuIGUucHVzaChuICsgIiAiKSA+IHIuY2FjaGVMZW5ndGggJiYgZGVsZXRlIHRbZS5zaGlmdCgpXSwgdFtuICsgIiAiXSA9IGkgfSByZXR1cm4gdCB9IGZ1bmN0aW9uIHVlKGUpIHsgcmV0dXJuIGVbeF0gPSAhMCwgZSB9IGZ1bmN0aW9uIHNlKGUpIHsgdmFyIHQgPSBwLmNyZWF0ZUVsZW1lbnQoImZpZWxkc2V0Iik7IHRyeSB7IHJldHVybiAhIWUodCkgfSBjYXRjaCAoZSkgeyByZXR1cm4gITEgfSBmaW5hbGx5IHsgdC5wYXJlbnROb2RlICYmIHQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0KSwgdCA9IG51bGwgfSB9IGZ1bmN0aW9uIGxlKGUsIHQpIHsgdmFyIG4gPSBlLnNwbGl0KCJ8IiksIGkgPSBuLmxlbmd0aDsgd2hpbGUgKGktLSkgci5hdHRySGFuZGxlW25baV1dID0gdCB9IGZ1bmN0aW9uIGNlKGUsIHQpIHsgdmFyIG4gPSB0ICYmIGUsIHIgPSBuICYmIDEgPT09IGUubm9kZVR5cGUgJiYgMSA9PT0gdC5ub2RlVHlwZSAmJiBlLnNvdXJjZUluZGV4IC0gdC5zb3VyY2VJbmRleDsgaWYgKHIpIHJldHVybiByOyBpZiAobikgd2hpbGUgKG4gPSBuLm5leHRTaWJsaW5nKSBpZiAobiA9PT0gdCkgcmV0dXJuIC0xOyByZXR1cm4gZSA/IDEgOiAtMSB9IGZ1bmN0aW9uIGZlKGUpIHsgcmV0dXJuIGZ1bmN0aW9uICh0KSB7IHJldHVybiAiaW5wdXQiID09PSB0Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgJiYgdC50eXBlID09PSBlIH0gfSBmdW5jdGlvbiBkZShlKSB7IHJldHVybiBmdW5jdGlvbiAodCkgeyB2YXIgbiA9IHQubm9kZU5hbWUudG9Mb3dlckNhc2UoKTsgcmV0dXJuICgiaW5wdXQiID09PSBuIHx8ICJidXR0b24iID09PSBuKSAmJiB0LnR5cGUgPT09IGUgfSB9IGZ1bmN0aW9uIHBlKGUpIHsgcmV0dXJuIGZ1bmN0aW9uICh0KSB7IHJldHVybiAiZm9ybSIgaW4gdCA/IHQucGFyZW50Tm9kZSAmJiAhMSA9PT0gdC5kaXNhYmxlZCA/ICJsYWJlbCIgaW4gdCA/ICJsYWJlbCIgaW4gdC5wYXJlbnROb2RlID8gdC5wYXJlbnROb2RlLmRpc2FibGVkID09PSBlIDogdC5kaXNhYmxlZCA9PT0gZSA6IHQuaXNEaXNhYmxlZCA9PT0gZSB8fCB0LmlzRGlzYWJsZWQgIT09ICFlICYmIGllKHQpID09PSBlIDogdC5kaXNhYmxlZCA9PT0gZSA6ICJsYWJlbCIgaW4gdCAmJiB0LmRpc2FibGVkID09PSBlIH0gfSBmdW5jdGlvbiBoZShlKSB7IHJldHVybiB1ZShmdW5jdGlvbiAodCkgeyByZXR1cm4gdCA9ICt0LCB1ZShmdW5jdGlvbiAobiwgcikgeyB2YXIgaSwgbyA9IGUoW10sIG4ubGVuZ3RoLCB0KSwgYSA9IG8ubGVuZ3RoOyB3aGlsZSAoYS0tKSBuW2kgPSBvW2FdXSAmJiAobltpXSA9ICEocltpXSA9IG5baV0pKSB9KSB9KSB9IGZ1bmN0aW9uIGdlKGUpIHsgcmV0dXJuIGUgJiYgInVuZGVmaW5lZCIgIT0gdHlwZW9mIGUuZ2V0RWxlbWVudHNCeVRhZ05hbWUgJiYgZSB9IG4gPSBvZS5zdXBwb3J0ID0ge30sIG8gPSBvZS5pc1hNTCA9IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZSAmJiAoZS5vd25lckRvY3VtZW50IHx8IGUpLmRvY3VtZW50RWxlbWVudDsgcmV0dXJuICEhdCAmJiAiSFRNTCIgIT09IHQubm9kZU5hbWUgfSwgZCA9IG9lLnNldERvY3VtZW50ID0gZnVuY3Rpb24gKGUpIHsgdmFyIHQsIGksIGEgPSBlID8gZS5vd25lckRvY3VtZW50IHx8IGUgOiB3OyByZXR1cm4gYSAhPT0gcCAmJiA5ID09PSBhLm5vZGVUeXBlICYmIGEuZG9jdW1lbnRFbGVtZW50ID8gKHAgPSBhLCBoID0gcC5kb2N1bWVudEVsZW1lbnQsIGcgPSAhbyhwKSwgdyAhPT0gcCAmJiAoaSA9IHAuZGVmYXVsdFZpZXcpICYmIGkudG9wICE9PSBpICYmIChpLmFkZEV2ZW50TGlzdGVuZXIgPyBpLmFkZEV2ZW50TGlzdGVuZXIoInVubG9hZCIsIHJlLCAhMSkgOiBpLmF0dGFjaEV2ZW50ICYmIGkuYXR0YWNoRXZlbnQoIm9udW5sb2FkIiwgcmUpKSwgbi5hdHRyaWJ1dGVzID0gc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUuY2xhc3NOYW1lID0gImkiLCAhZS5nZXRBdHRyaWJ1dGUoImNsYXNzTmFtZSIpIH0pLCBuLmdldEVsZW1lbnRzQnlUYWdOYW1lID0gc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUuYXBwZW5kQ2hpbGQocC5jcmVhdGVDb21tZW50KCIiKSksICFlLmdldEVsZW1lbnRzQnlUYWdOYW1lKCIqIikubGVuZ3RoIH0pLCBuLmdldEVsZW1lbnRzQnlDbGFzc05hbWUgPSBHLnRlc3QocC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKSwgbi5nZXRCeUlkID0gc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGguYXBwZW5kQ2hpbGQoZSkuaWQgPSB4LCAhcC5nZXRFbGVtZW50c0J5TmFtZSB8fCAhcC5nZXRFbGVtZW50c0J5TmFtZSh4KS5sZW5ndGggfSksIG4uZ2V0QnlJZCA/IChyLmZpbHRlci5JRCA9IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZS5yZXBsYWNlKFosIGVlKTsgcmV0dXJuIGZ1bmN0aW9uIChlKSB7IHJldHVybiBlLmdldEF0dHJpYnV0ZSgiaWQiKSA9PT0gdCB9IH0sIHIuZmluZC5JRCA9IGZ1bmN0aW9uIChlLCB0KSB7IGlmICgidW5kZWZpbmVkIiAhPSB0eXBlb2YgdC5nZXRFbGVtZW50QnlJZCAmJiBnKSB7IHZhciBuID0gdC5nZXRFbGVtZW50QnlJZChlKTsgcmV0dXJuIG4gPyBbbl0gOiBbXSB9IH0pIDogKHIuZmlsdGVyLklEID0gZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSBlLnJlcGxhY2UoWiwgZWUpOyByZXR1cm4gZnVuY3Rpb24gKGUpIHsgdmFyIG4gPSAidW5kZWZpbmVkIiAhPSB0eXBlb2YgZS5nZXRBdHRyaWJ1dGVOb2RlICYmIGUuZ2V0QXR0cmlidXRlTm9kZSgiaWQiKTsgcmV0dXJuIG4gJiYgbi52YWx1ZSA9PT0gdCB9IH0sIHIuZmluZC5JRCA9IGZ1bmN0aW9uIChlLCB0KSB7IGlmICgidW5kZWZpbmVkIiAhPSB0eXBlb2YgdC5nZXRFbGVtZW50QnlJZCAmJiBnKSB7IHZhciBuLCByLCBpLCBvID0gdC5nZXRFbGVtZW50QnlJZChlKTsgaWYgKG8pIHsgaWYgKChuID0gby5nZXRBdHRyaWJ1dGVOb2RlKCJpZCIpKSAmJiBuLnZhbHVlID09PSBlKSByZXR1cm4gW29dOyBpID0gdC5nZXRFbGVtZW50c0J5TmFtZShlKSwgciA9IDA7IHdoaWxlIChvID0gaVtyKytdKSBpZiAoKG4gPSBvLmdldEF0dHJpYnV0ZU5vZGUoImlkIikpICYmIG4udmFsdWUgPT09IGUpIHJldHVybiBbb10gfSByZXR1cm4gW10gfSB9KSwgci5maW5kLlRBRyA9IG4uZ2V0RWxlbWVudHNCeVRhZ05hbWUgPyBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gInVuZGVmaW5lZCIgIT0gdHlwZW9mIHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUgPyB0LmdldEVsZW1lbnRzQnlUYWdOYW1lKGUpIDogbi5xc2EgPyB0LnF1ZXJ5U2VsZWN0b3JBbGwoZSkgOiB2b2lkIDAgfSA6IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCByID0gW10sIGkgPSAwLCBvID0gdC5nZXRFbGVtZW50c0J5VGFnTmFtZShlKTsgaWYgKCIqIiA9PT0gZSkgeyB3aGlsZSAobiA9IG9baSsrXSkgMSA9PT0gbi5ub2RlVHlwZSAmJiByLnB1c2gobik7IHJldHVybiByIH0gcmV0dXJuIG8gfSwgci5maW5kLkNMQVNTID0gbi5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lICYmIGZ1bmN0aW9uIChlLCB0KSB7IGlmICgidW5kZWZpbmVkIiAhPSB0eXBlb2YgdC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lICYmIGcpIHJldHVybiB0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoZSkgfSwgeSA9IFtdLCB2ID0gW10sIChuLnFzYSA9IEcudGVzdChwLnF1ZXJ5U2VsZWN0b3JBbGwpKSAmJiAoc2UoZnVuY3Rpb24gKGUpIHsgaC5hcHBlbmRDaGlsZChlKS5pbm5lckhUTUwgPSAiPGEgaWQ9JyIgKyB4ICsgIic+PC9hPjxzZWxlY3QgaWQ9JyIgKyB4ICsgIi1cclxcJyBtc2FsbG93Y2FwdHVyZT0nJz48b3B0aW9uIHNlbGVjdGVkPScnPjwvb3B0aW9uPjwvc2VsZWN0PiIsIGUucXVlcnlTZWxlY3RvckFsbCgiW21zYWxsb3djYXB0dXJlXj0nJ10iKS5sZW5ndGggJiYgdi5wdXNoKCJbKl4kXT0iICsgSSArICIqKD86Jyd8XCJcIikiKSwgZS5xdWVyeVNlbGVjdG9yQWxsKCJbc2VsZWN0ZWRdIikubGVuZ3RoIHx8IHYucHVzaCgiXFxbIiArIEkgKyAiKig/OnZhbHVlfCIgKyBIICsgIikiKSwgZS5xdWVyeVNlbGVjdG9yQWxsKCJbaWR+PSIgKyB4ICsgIi1dIikubGVuZ3RoIHx8IHYucHVzaCgifj0iKSwgZS5xdWVyeVNlbGVjdG9yQWxsKCI6Y2hlY2tlZCIpLmxlbmd0aCB8fCB2LnB1c2goIjpjaGVja2VkIiksIGUucXVlcnlTZWxlY3RvckFsbCgiYSMiICsgeCArICIrKiIpLmxlbmd0aCB8fCB2LnB1c2goIi4jLitbK35dIikgfSksIHNlKGZ1bmN0aW9uIChlKSB7IGUuaW5uZXJIVE1MID0gIjxhIGhyZWY9JycgZGlzYWJsZWQ9J2Rpc2FibGVkJz48L2E+PHNlbGVjdCBkaXNhYmxlZD0nZGlzYWJsZWQnPjxvcHRpb24vPjwvc2VsZWN0PiI7IHZhciB0ID0gcC5jcmVhdGVFbGVtZW50KCJpbnB1dCIpOyB0LnNldEF0dHJpYnV0ZSgidHlwZSIsICJoaWRkZW4iKSwgZS5hcHBlbmRDaGlsZCh0KS5zZXRBdHRyaWJ1dGUoIm5hbWUiLCAiRCIpLCBlLnF1ZXJ5U2VsZWN0b3JBbGwoIltuYW1lPWRdIikubGVuZ3RoICYmIHYucHVzaCgibmFtZSIgKyBJICsgIipbKl4kfCF+XT89IiksIDIgIT09IGUucXVlcnlTZWxlY3RvckFsbCgiOmVuYWJsZWQiKS5sZW5ndGggJiYgdi5wdXNoKCI6ZW5hYmxlZCIsICI6ZGlzYWJsZWQiKSwgaC5hcHBlbmRDaGlsZChlKS5kaXNhYmxlZCA9ICEwLCAyICE9PSBlLnF1ZXJ5U2VsZWN0b3JBbGwoIjpkaXNhYmxlZCIpLmxlbmd0aCAmJiB2LnB1c2goIjplbmFibGVkIiwgIjpkaXNhYmxlZCIpLCBlLnF1ZXJ5U2VsZWN0b3JBbGwoIiosOngiKSwgdi5wdXNoKCIsLio6IikgfSkpLCAobi5tYXRjaGVzU2VsZWN0b3IgPSBHLnRlc3QobSA9IGgubWF0Y2hlcyB8fCBoLndlYmtpdE1hdGNoZXNTZWxlY3RvciB8fCBoLm1vek1hdGNoZXNTZWxlY3RvciB8fCBoLm9NYXRjaGVzU2VsZWN0b3IgfHwgaC5tc01hdGNoZXNTZWxlY3RvcikpICYmIHNlKGZ1bmN0aW9uIChlKSB7IG4uZGlzY29ubmVjdGVkTWF0Y2ggPSBtLmNhbGwoZSwgIioiKSwgbS5jYWxsKGUsICJbcyE9JyddOngiKSwgeS5wdXNoKCIhPSIsIE0pIH0pLCB2ID0gdi5sZW5ndGggJiYgbmV3IFJlZ0V4cCh2LmpvaW4oInwiKSksIHkgPSB5Lmxlbmd0aCAmJiBuZXcgUmVnRXhwKHkuam9pbigifCIpKSwgdCA9IEcudGVzdChoLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKSwgYiA9IHQgfHwgRy50ZXN0KGguY29udGFpbnMpID8gZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4gPSA5ID09PSBlLm5vZGVUeXBlID8gZS5kb2N1bWVudEVsZW1lbnQgOiBlLCByID0gdCAmJiB0LnBhcmVudE5vZGU7IHJldHVybiBlID09PSByIHx8ICEoIXIgfHwgMSAhPT0gci5ub2RlVHlwZSB8fCAhKG4uY29udGFpbnMgPyBuLmNvbnRhaW5zKHIpIDogZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiAmJiAxNiAmIGUuY29tcGFyZURvY3VtZW50UG9zaXRpb24ocikpKSB9IDogZnVuY3Rpb24gKGUsIHQpIHsgaWYgKHQpIHdoaWxlICh0ID0gdC5wYXJlbnROb2RlKSBpZiAodCA9PT0gZSkgcmV0dXJuICEwOyByZXR1cm4gITEgfSwgQSA9IHQgPyBmdW5jdGlvbiAoZSwgdCkgeyBpZiAoZSA9PT0gdCkgcmV0dXJuIGYgPSAhMCwgMDsgdmFyIHIgPSAhZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiAtICF0LmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uOyByZXR1cm4gciB8fCAoMSAmIChyID0gKGUub3duZXJEb2N1bWVudCB8fCBlKSA9PT0gKHQub3duZXJEb2N1bWVudCB8fCB0KSA/IGUuY29tcGFyZURvY3VtZW50UG9zaXRpb24odCkgOiAxKSB8fCAhbi5zb3J0RGV0YWNoZWQgJiYgdC5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihlKSA9PT0gciA/IGUgPT09IHAgfHwgZS5vd25lckRvY3VtZW50ID09PSB3ICYmIGIodywgZSkgPyAtMSA6IHQgPT09IHAgfHwgdC5vd25lckRvY3VtZW50ID09PSB3ICYmIGIodywgdCkgPyAxIDogYyA/IFAoYywgZSkgLSBQKGMsIHQpIDogMCA6IDQgJiByID8gLTEgOiAxKSB9IDogZnVuY3Rpb24gKGUsIHQpIHsgaWYgKGUgPT09IHQpIHJldHVybiBmID0gITAsIDA7IHZhciBuLCByID0gMCwgaSA9IGUucGFyZW50Tm9kZSwgbyA9IHQucGFyZW50Tm9kZSwgYSA9IFtlXSwgdSA9IFt0XTsgaWYgKCFpIHx8ICFvKSByZXR1cm4gZSA9PT0gcCA/IC0xIDogdCA9PT0gcCA/IDEgOiBpID8gLTEgOiBvID8gMSA6IGMgPyBQKGMsIGUpIC0gUChjLCB0KSA6IDA7IGlmIChpID09PSBvKSByZXR1cm4gY2UoZSwgdCk7IG4gPSBlOyB3aGlsZSAobiA9IG4ucGFyZW50Tm9kZSkgYS51bnNoaWZ0KG4pOyBuID0gdDsgd2hpbGUgKG4gPSBuLnBhcmVudE5vZGUpIHUudW5zaGlmdChuKTsgd2hpbGUgKGFbcl0gPT09IHVbcl0pIHIrKzsgcmV0dXJuIHIgPyBjZShhW3JdLCB1W3JdKSA6IGFbcl0gPT09IHcgPyAtMSA6IHVbcl0gPT09IHcgPyAxIDogMCB9LCBwKSA6IHAgfSwgb2UubWF0Y2hlcyA9IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiBvZShlLCBudWxsLCBudWxsLCB0KSB9LCBvZS5tYXRjaGVzU2VsZWN0b3IgPSBmdW5jdGlvbiAoZSwgdCkgeyBpZiAoKGUub3duZXJEb2N1bWVudCB8fCBlKSAhPT0gcCAmJiBkKGUpLCB0ID0gdC5yZXBsYWNlKF8sICI9JyQxJ10iKSwgbi5tYXRjaGVzU2VsZWN0b3IgJiYgZyAmJiAha1t0ICsgIiAiXSAmJiAoIXkgfHwgIXkudGVzdCh0KSkgJiYgKCF2IHx8ICF2LnRlc3QodCkpKSB0cnkgeyB2YXIgciA9IG0uY2FsbChlLCB0KTsgaWYgKHIgfHwgbi5kaXNjb25uZWN0ZWRNYXRjaCB8fCBlLmRvY3VtZW50ICYmIDExICE9PSBlLmRvY3VtZW50Lm5vZGVUeXBlKSByZXR1cm4gciB9IGNhdGNoIChlKSB7IH0gcmV0dXJuIG9lKHQsIHAsIG51bGwsIFtlXSkubGVuZ3RoID4gMCB9LCBvZS5jb250YWlucyA9IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiAoZS5vd25lckRvY3VtZW50IHx8IGUpICE9PSBwICYmIGQoZSksIGIoZSwgdCkgfSwgb2UuYXR0ciA9IGZ1bmN0aW9uIChlLCB0KSB7IChlLm93bmVyRG9jdW1lbnQgfHwgZSkgIT09IHAgJiYgZChlKTsgdmFyIGkgPSByLmF0dHJIYW5kbGVbdC50b0xvd2VyQ2FzZSgpXSwgbyA9IGkgJiYgRC5jYWxsKHIuYXR0ckhhbmRsZSwgdC50b0xvd2VyQ2FzZSgpKSA/IGkoZSwgdCwgIWcpIDogdm9pZCAwOyByZXR1cm4gdm9pZCAwICE9PSBvID8gbyA6IG4uYXR0cmlidXRlcyB8fCAhZyA/IGUuZ2V0QXR0cmlidXRlKHQpIDogKG8gPSBlLmdldEF0dHJpYnV0ZU5vZGUodCkpICYmIG8uc3BlY2lmaWVkID8gby52YWx1ZSA6IG51bGwgfSwgb2UuZXNjYXBlID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuIChlICsgIiIpLnJlcGxhY2UodGUsIG5lKSB9LCBvZS5lcnJvciA9IGZ1bmN0aW9uIChlKSB7IHRocm93IG5ldyBFcnJvcigiU3ludGF4IGVycm9yLCB1bnJlY29nbml6ZWQgZXhwcmVzc2lvbjogIiArIGUpIH0sIG9lLnVuaXF1ZVNvcnQgPSBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgciA9IFtdLCBpID0gMCwgbyA9IDA7IGlmIChmID0gIW4uZGV0ZWN0RHVwbGljYXRlcywgYyA9ICFuLnNvcnRTdGFibGUgJiYgZS5zbGljZSgwKSwgZS5zb3J0KEEpLCBmKSB7IHdoaWxlICh0ID0gZVtvKytdKSB0ID09PSBlW29dICYmIChpID0gci5wdXNoKG8pKTsgd2hpbGUgKGktLSkgZS5zcGxpY2UocltpXSwgMSkgfSByZXR1cm4gYyA9IG51bGwsIGUgfSwgaSA9IG9lLmdldFRleHQgPSBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgbiA9ICIiLCByID0gMCwgbyA9IGUubm9kZVR5cGU7IGlmIChvKSB7IGlmICgxID09PSBvIHx8IDkgPT09IG8gfHwgMTEgPT09IG8pIHsgaWYgKCJzdHJpbmciID09IHR5cGVvZiBlLnRleHRDb250ZW50KSByZXR1cm4gZS50ZXh0Q29udGVudDsgZm9yIChlID0gZS5maXJzdENoaWxkOyBlOyBlID0gZS5uZXh0U2libGluZyluICs9IGkoZSkgfSBlbHNlIGlmICgzID09PSBvIHx8IDQgPT09IG8pIHJldHVybiBlLm5vZGVWYWx1ZSB9IGVsc2Ugd2hpbGUgKHQgPSBlW3IrK10pIG4gKz0gaSh0KTsgcmV0dXJuIG4gfSwgKHIgPSBvZS5zZWxlY3RvcnMgPSB7IGNhY2hlTGVuZ3RoOiA1MCwgY3JlYXRlUHNldWRvOiB1ZSwgbWF0Y2g6IFgsIGF0dHJIYW5kbGU6IHt9LCBmaW5kOiB7fSwgcmVsYXRpdmU6IHsgIj4iOiB7IGRpcjogInBhcmVudE5vZGUiLCBmaXJzdDogITAgfSwgIiAiOiB7IGRpcjogInBhcmVudE5vZGUiIH0sICIrIjogeyBkaXI6ICJwcmV2aW91c1NpYmxpbmciLCBmaXJzdDogITAgfSwgIn4iOiB7IGRpcjogInByZXZpb3VzU2libGluZyIgfSB9LCBwcmVGaWx0ZXI6IHsgQVRUUjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGVbMV0gPSBlWzFdLnJlcGxhY2UoWiwgZWUpLCBlWzNdID0gKGVbM10gfHwgZVs0XSB8fCBlWzVdIHx8ICIiKS5yZXBsYWNlKFosIGVlKSwgIn49IiA9PT0gZVsyXSAmJiAoZVszXSA9ICIgIiArIGVbM10gKyAiICIpLCBlLnNsaWNlKDAsIDQpIH0sIENISUxEOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZVsxXSA9IGVbMV0udG9Mb3dlckNhc2UoKSwgIm50aCIgPT09IGVbMV0uc2xpY2UoMCwgMykgPyAoZVszXSB8fCBvZS5lcnJvcihlWzBdKSwgZVs0XSA9ICsoZVs0XSA/IGVbNV0gKyAoZVs2XSB8fCAxKSA6IDIgKiAoImV2ZW4iID09PSBlWzNdIHx8ICJvZGQiID09PSBlWzNdKSksIGVbNV0gPSArKGVbN10gKyBlWzhdIHx8ICJvZGQiID09PSBlWzNdKSkgOiBlWzNdICYmIG9lLmVycm9yKGVbMF0pLCBlIH0sIFBTRVVETzogZnVuY3Rpb24gKGUpIHsgdmFyIHQsIG4gPSAhZVs2XSAmJiBlWzJdOyByZXR1cm4gWC5DSElMRC50ZXN0KGVbMF0pID8gbnVsbCA6IChlWzNdID8gZVsyXSA9IGVbNF0gfHwgZVs1XSB8fCAiIiA6IG4gJiYgVS50ZXN0KG4pICYmICh0ID0gYShuLCAhMCkpICYmICh0ID0gbi5pbmRleE9mKCIpIiwgbi5sZW5ndGggLSB0KSAtIG4ubGVuZ3RoKSAmJiAoZVswXSA9IGVbMF0uc2xpY2UoMCwgdCksIGVbMl0gPSBuLnNsaWNlKDAsIHQpKSwgZS5zbGljZSgwLCAzKSkgfSB9LCBmaWx0ZXI6IHsgVEFHOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGUucmVwbGFjZShaLCBlZSkudG9Mb3dlckNhc2UoKTsgcmV0dXJuICIqIiA9PT0gZSA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuICEwIH0gOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZS5ub2RlTmFtZSAmJiBlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IHQgfSB9LCBDTEFTUzogZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSBFW2UgKyAiICJdOyByZXR1cm4gdCB8fCAodCA9IG5ldyBSZWdFeHAoIihefCIgKyBJICsgIikiICsgZSArICIoIiArIEkgKyAifCQpIikpICYmIEUoZSwgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHQudGVzdCgic3RyaW5nIiA9PSB0eXBlb2YgZS5jbGFzc05hbWUgJiYgZS5jbGFzc05hbWUgfHwgInVuZGVmaW5lZCIgIT0gdHlwZW9mIGUuZ2V0QXR0cmlidXRlICYmIGUuZ2V0QXR0cmlidXRlKCJjbGFzcyIpIHx8ICIiKSB9KSB9LCBBVFRSOiBmdW5jdGlvbiAoZSwgdCwgbikgeyByZXR1cm4gZnVuY3Rpb24gKHIpIHsgdmFyIGkgPSBvZS5hdHRyKHIsIGUpOyByZXR1cm4gbnVsbCA9PSBpID8gIiE9IiA9PT0gdCA6ICF0IHx8IChpICs9ICIiLCAiPSIgPT09IHQgPyBpID09PSBuIDogIiE9IiA9PT0gdCA/IGkgIT09IG4gOiAiXj0iID09PSB0ID8gbiAmJiAwID09PSBpLmluZGV4T2YobikgOiAiKj0iID09PSB0ID8gbiAmJiBpLmluZGV4T2YobikgPiAtMSA6ICIkPSIgPT09IHQgPyBuICYmIGkuc2xpY2UoLW4ubGVuZ3RoKSA9PT0gbiA6ICJ+PSIgPT09IHQgPyAoIiAiICsgaS5yZXBsYWNlKFcsICIgIikgKyAiICIpLmluZGV4T2YobikgPiAtMSA6ICJ8PSIgPT09IHQgJiYgKGkgPT09IG4gfHwgaS5zbGljZSgwLCBuLmxlbmd0aCArIDEpID09PSBuICsgIi0iKSkgfSB9LCBDSElMRDogZnVuY3Rpb24gKGUsIHQsIG4sIHIsIGkpIHsgdmFyIG8gPSAibnRoIiAhPT0gZS5zbGljZSgwLCAzKSwgYSA9ICJsYXN0IiAhPT0gZS5zbGljZSgtNCksIHUgPSAib2YtdHlwZSIgPT09IHQ7IHJldHVybiAxID09PSByICYmIDAgPT09IGkgPyBmdW5jdGlvbiAoZSkgeyByZXR1cm4gISFlLnBhcmVudE5vZGUgfSA6IGZ1bmN0aW9uICh0LCBuLCBzKSB7IHZhciBsLCBjLCBmLCBkLCBwLCBoLCBnID0gbyAhPT0gYSA/ICJuZXh0U2libGluZyIgOiAicHJldmlvdXNTaWJsaW5nIiwgdiA9IHQucGFyZW50Tm9kZSwgeSA9IHUgJiYgdC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpLCBtID0gIXMgJiYgIXUsIGIgPSAhMTsgaWYgKHYpIHsgaWYgKG8pIHsgd2hpbGUgKGcpIHsgZCA9IHQ7IHdoaWxlIChkID0gZFtnXSkgaWYgKHUgPyBkLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IHkgOiAxID09PSBkLm5vZGVUeXBlKSByZXR1cm4gITE7IGggPSBnID0gIm9ubHkiID09PSBlICYmICFoICYmICJuZXh0U2libGluZyIgfSByZXR1cm4gITAgfSBpZiAoaCA9IFthID8gdi5maXJzdENoaWxkIDogdi5sYXN0Q2hpbGRdLCBhICYmIG0pIHsgYiA9IChwID0gKGwgPSAoYyA9IChmID0gKGQgPSB2KVt4XSB8fCAoZFt4XSA9IHt9KSlbZC51bmlxdWVJRF0gfHwgKGZbZC51bmlxdWVJRF0gPSB7fSkpW2VdIHx8IFtdKVswXSA9PT0gQyAmJiBsWzFdKSAmJiBsWzJdLCBkID0gcCAmJiB2LmNoaWxkTm9kZXNbcF07IHdoaWxlIChkID0gKytwICYmIGQgJiYgZFtnXSB8fCAoYiA9IHAgPSAwKSB8fCBoLnBvcCgpKSBpZiAoMSA9PT0gZC5ub2RlVHlwZSAmJiArK2IgJiYgZCA9PT0gdCkgeyBjW2VdID0gW0MsIHAsIGJdOyBicmVhayB9IH0gZWxzZSBpZiAobSAmJiAoYiA9IHAgPSAobCA9IChjID0gKGYgPSAoZCA9IHQpW3hdIHx8IChkW3hdID0ge30pKVtkLnVuaXF1ZUlEXSB8fCAoZltkLnVuaXF1ZUlEXSA9IHt9KSlbZV0gfHwgW10pWzBdID09PSBDICYmIGxbMV0pLCAhMSA9PT0gYikgd2hpbGUgKGQgPSArK3AgJiYgZCAmJiBkW2ddIHx8IChiID0gcCA9IDApIHx8IGgucG9wKCkpIGlmICgodSA/IGQubm9kZU5hbWUudG9Mb3dlckNhc2UoKSA9PT0geSA6IDEgPT09IGQubm9kZVR5cGUpICYmICsrYiAmJiAobSAmJiAoKGMgPSAoZiA9IGRbeF0gfHwgKGRbeF0gPSB7fSkpW2QudW5pcXVlSURdIHx8IChmW2QudW5pcXVlSURdID0ge30pKVtlXSA9IFtDLCBiXSksIGQgPT09IHQpKSBicmVhazsgcmV0dXJuIChiIC09IGkpID09PSByIHx8IGIgJSByID09IDAgJiYgYiAvIHIgPj0gMCB9IH0gfSwgUFNFVURPOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiwgaSA9IHIucHNldWRvc1tlXSB8fCByLnNldEZpbHRlcnNbZS50b0xvd2VyQ2FzZSgpXSB8fCBvZS5lcnJvcigidW5zdXBwb3J0ZWQgcHNldWRvOiAiICsgZSk7IHJldHVybiBpW3hdID8gaSh0KSA6IGkubGVuZ3RoID4gMSA/IChuID0gW2UsIGUsICIiLCB0XSwgci5zZXRGaWx0ZXJzLmhhc093blByb3BlcnR5KGUudG9Mb3dlckNhc2UoKSkgPyB1ZShmdW5jdGlvbiAoZSwgbikgeyB2YXIgciwgbyA9IGkoZSwgdCksIGEgPSBvLmxlbmd0aDsgd2hpbGUgKGEtLSkgZVtyID0gUChlLCBvW2FdKV0gPSAhKG5bcl0gPSBvW2FdKSB9KSA6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBpKGUsIDAsIG4pIH0pIDogaSB9IH0sIHBzZXVkb3M6IHsgbm90OiB1ZShmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IFtdLCBuID0gW10sIHIgPSB1KGUucmVwbGFjZSgkLCAiJDEiKSk7IHJldHVybiByW3hdID8gdWUoZnVuY3Rpb24gKGUsIHQsIG4sIGkpIHsgdmFyIG8sIGEgPSByKGUsIG51bGwsIGksIFtdKSwgdSA9IGUubGVuZ3RoOyB3aGlsZSAodS0tKSAobyA9IGFbdV0pICYmIChlW3VdID0gISh0W3VdID0gbykpIH0pIDogZnVuY3Rpb24gKGUsIGksIG8pIHsgcmV0dXJuIHRbMF0gPSBlLCByKHQsIG51bGwsIG8sIG4pLCB0WzBdID0gbnVsbCwgIW4ucG9wKCkgfSB9KSwgaGFzOiB1ZShmdW5jdGlvbiAoZSkgeyByZXR1cm4gZnVuY3Rpb24gKHQpIHsgcmV0dXJuIG9lKGUsIHQpLmxlbmd0aCA+IDAgfSB9KSwgY29udGFpbnM6IHVlKGZ1bmN0aW9uIChlKSB7IHJldHVybiBlID0gZS5yZXBsYWNlKFosIGVlKSwgZnVuY3Rpb24gKHQpIHsgcmV0dXJuICh0LnRleHRDb250ZW50IHx8IHQuaW5uZXJUZXh0IHx8IGkodCkpLmluZGV4T2YoZSkgPiAtMSB9IH0pLCBsYW5nOiB1ZShmdW5jdGlvbiAoZSkgeyByZXR1cm4gVi50ZXN0KGUgfHwgIiIpIHx8IG9lLmVycm9yKCJ1bnN1cHBvcnRlZCBsYW5nOiAiICsgZSksIGUgPSBlLnJlcGxhY2UoWiwgZWUpLnRvTG93ZXJDYXNlKCksIGZ1bmN0aW9uICh0KSB7IHZhciBuOyBkbyB7IGlmIChuID0gZyA/IHQubGFuZyA6IHQuZ2V0QXR0cmlidXRlKCJ4bWw6bGFuZyIpIHx8IHQuZ2V0QXR0cmlidXRlKCJsYW5nIikpIHJldHVybiAobiA9IG4udG9Mb3dlckNhc2UoKSkgPT09IGUgfHwgMCA9PT0gbi5pbmRleE9mKGUgKyAiLSIpIH0gd2hpbGUgKCh0ID0gdC5wYXJlbnROb2RlKSAmJiAxID09PSB0Lm5vZGVUeXBlKTsgcmV0dXJuICExIH0gfSksIHRhcmdldDogZnVuY3Rpb24gKHQpIHsgdmFyIG4gPSBlLmxvY2F0aW9uICYmIGUubG9jYXRpb24uaGFzaDsgcmV0dXJuIG4gJiYgbi5zbGljZSgxKSA9PT0gdC5pZCB9LCByb290OiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZSA9PT0gaCB9LCBmb2N1czogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUgPT09IHAuYWN0aXZlRWxlbWVudCAmJiAoIXAuaGFzRm9jdXMgfHwgcC5oYXNGb2N1cygpKSAmJiAhIShlLnR5cGUgfHwgZS5ocmVmIHx8IH5lLnRhYkluZGV4KSB9LCBlbmFibGVkOiBwZSghMSksIGRpc2FibGVkOiBwZSghMCksIGNoZWNrZWQ6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpOyByZXR1cm4gImlucHV0IiA9PT0gdCAmJiAhIWUuY2hlY2tlZCB8fCAib3B0aW9uIiA9PT0gdCAmJiAhIWUuc2VsZWN0ZWQgfSwgc2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBlLnBhcmVudE5vZGUgJiYgZS5wYXJlbnROb2RlLnNlbGVjdGVkSW5kZXgsICEwID09PSBlLnNlbGVjdGVkIH0sIGVtcHR5OiBmdW5jdGlvbiAoZSkgeyBmb3IgKGUgPSBlLmZpcnN0Q2hpbGQ7IGU7IGUgPSBlLm5leHRTaWJsaW5nKWlmIChlLm5vZGVUeXBlIDwgNikgcmV0dXJuICExOyByZXR1cm4gITAgfSwgcGFyZW50OiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gIXIucHNldWRvcy5lbXB0eShlKSB9LCBoZWFkZXI6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBZLnRlc3QoZS5ub2RlTmFtZSkgfSwgaW5wdXQ6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBRLnRlc3QoZS5ub2RlTmFtZSkgfSwgYnV0dG9uOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGUubm9kZU5hbWUudG9Mb3dlckNhc2UoKTsgcmV0dXJuICJpbnB1dCIgPT09IHQgJiYgImJ1dHRvbiIgPT09IGUudHlwZSB8fCAiYnV0dG9uIiA9PT0gdCB9LCB0ZXh0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdDsgcmV0dXJuICJpbnB1dCIgPT09IGUubm9kZU5hbWUudG9Mb3dlckNhc2UoKSAmJiAidGV4dCIgPT09IGUudHlwZSAmJiAobnVsbCA9PSAodCA9IGUuZ2V0QXR0cmlidXRlKCJ0eXBlIikpIHx8ICJ0ZXh0IiA9PT0gdC50b0xvd2VyQ2FzZSgpKSB9LCBmaXJzdDogaGUoZnVuY3Rpb24gKCkgeyByZXR1cm4gWzBdIH0pLCBsYXN0OiBoZShmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gW3QgLSAxXSB9KSwgZXE6IGhlKGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBbbiA8IDAgPyBuICsgdCA6IG5dIH0pLCBldmVuOiBoZShmdW5jdGlvbiAoZSwgdCkgeyBmb3IgKHZhciBuID0gMDsgbiA8IHQ7IG4gKz0gMillLnB1c2gobik7IHJldHVybiBlIH0pLCBvZGQ6IGhlKGZ1bmN0aW9uIChlLCB0KSB7IGZvciAodmFyIG4gPSAxOyBuIDwgdDsgbiArPSAyKWUucHVzaChuKTsgcmV0dXJuIGUgfSksIGx0OiBoZShmdW5jdGlvbiAoZSwgdCwgbikgeyBmb3IgKHZhciByID0gbiA8IDAgPyBuICsgdCA6IG47IC0tciA+PSAwOyllLnB1c2gocik7IHJldHVybiBlIH0pLCBndDogaGUoZnVuY3Rpb24gKGUsIHQsIG4pIHsgZm9yICh2YXIgciA9IG4gPCAwID8gbiArIHQgOiBuOyArK3IgPCB0OyllLnB1c2gocik7IHJldHVybiBlIH0pIH0gfSkucHNldWRvcy5udGggPSByLnBzZXVkb3MuZXE7IGZvciAodCBpbiB7IHJhZGlvOiAhMCwgY2hlY2tib3g6ICEwLCBmaWxlOiAhMCwgcGFzc3dvcmQ6ICEwLCBpbWFnZTogITAgfSkgci5wc2V1ZG9zW3RdID0gZmUodCk7IGZvciAodCBpbiB7IHN1Ym1pdDogITAsIHJlc2V0OiAhMCB9KSByLnBzZXVkb3NbdF0gPSBkZSh0KTsgZnVuY3Rpb24gdmUoKSB7IH0gdmUucHJvdG90eXBlID0gci5maWx0ZXJzID0gci5wc2V1ZG9zLCByLnNldEZpbHRlcnMgPSBuZXcgdmUsIGEgPSBvZS50b2tlbml6ZSA9IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCBpLCBvLCBhLCB1LCBzLCBsLCBjID0gTltlICsgIiAiXTsgaWYgKGMpIHJldHVybiB0ID8gMCA6IGMuc2xpY2UoMCk7IHUgPSBlLCBzID0gW10sIGwgPSByLnByZUZpbHRlcjsgd2hpbGUgKHUpIHsgbiAmJiAhKGkgPSBGLmV4ZWModSkpIHx8IChpICYmICh1ID0gdS5zbGljZShpWzBdLmxlbmd0aCkgfHwgdSksIHMucHVzaChvID0gW10pKSwgbiA9ICExLCAoaSA9IHouZXhlYyh1KSkgJiYgKG4gPSBpLnNoaWZ0KCksIG8ucHVzaCh7IHZhbHVlOiBuLCB0eXBlOiBpWzBdLnJlcGxhY2UoJCwgIiAiKSB9KSwgdSA9IHUuc2xpY2Uobi5sZW5ndGgpKTsgZm9yIChhIGluIHIuZmlsdGVyKSAhKGkgPSBYW2FdLmV4ZWModSkpIHx8IGxbYV0gJiYgIShpID0gbFthXShpKSkgfHwgKG4gPSBpLnNoaWZ0KCksIG8ucHVzaCh7IHZhbHVlOiBuLCB0eXBlOiBhLCBtYXRjaGVzOiBpIH0pLCB1ID0gdS5zbGljZShuLmxlbmd0aCkpOyBpZiAoIW4pIGJyZWFrIH0gcmV0dXJuIHQgPyB1Lmxlbmd0aCA6IHUgPyBvZS5lcnJvcihlKSA6IE4oZSwgcykuc2xpY2UoMCkgfTsgZnVuY3Rpb24geWUoZSkgeyBmb3IgKHZhciB0ID0gMCwgbiA9IGUubGVuZ3RoLCByID0gIiI7IHQgPCBuOyB0KyspciArPSBlW3RdLnZhbHVlOyByZXR1cm4gciB9IGZ1bmN0aW9uIG1lKGUsIHQsIG4pIHsgdmFyIHIgPSB0LmRpciwgaSA9IHQubmV4dCwgbyA9IGkgfHwgciwgYSA9IG4gJiYgInBhcmVudE5vZGUiID09PSBvLCB1ID0gVCsrOyByZXR1cm4gdC5maXJzdCA/IGZ1bmN0aW9uICh0LCBuLCBpKSB7IHdoaWxlICh0ID0gdFtyXSkgaWYgKDEgPT09IHQubm9kZVR5cGUgfHwgYSkgcmV0dXJuIGUodCwgbiwgaSk7IHJldHVybiAhMSB9IDogZnVuY3Rpb24gKHQsIG4sIHMpIHsgdmFyIGwsIGMsIGYsIGQgPSBbQywgdV07IGlmIChzKSB7IHdoaWxlICh0ID0gdFtyXSkgaWYgKCgxID09PSB0Lm5vZGVUeXBlIHx8IGEpICYmIGUodCwgbiwgcykpIHJldHVybiAhMCB9IGVsc2Ugd2hpbGUgKHQgPSB0W3JdKSBpZiAoMSA9PT0gdC5ub2RlVHlwZSB8fCBhKSBpZiAoZiA9IHRbeF0gfHwgKHRbeF0gPSB7fSksIGMgPSBmW3QudW5pcXVlSURdIHx8IChmW3QudW5pcXVlSURdID0ge30pLCBpICYmIGkgPT09IHQubm9kZU5hbWUudG9Mb3dlckNhc2UoKSkgdCA9IHRbcl0gfHwgdDsgZWxzZSB7IGlmICgobCA9IGNbb10pICYmIGxbMF0gPT09IEMgJiYgbFsxXSA9PT0gdSkgcmV0dXJuIGRbMl0gPSBsWzJdOyBpZiAoY1tvXSA9IGQsIGRbMl0gPSBlKHQsIG4sIHMpKSByZXR1cm4gITAgfSByZXR1cm4gITEgfSB9IGZ1bmN0aW9uIGJlKGUpIHsgcmV0dXJuIGUubGVuZ3RoID4gMSA/IGZ1bmN0aW9uICh0LCBuLCByKSB7IHZhciBpID0gZS5sZW5ndGg7IHdoaWxlIChpLS0pIGlmICghZVtpXSh0LCBuLCByKSkgcmV0dXJuICExOyByZXR1cm4gITAgfSA6IGVbMF0gfSBmdW5jdGlvbiB4ZShlLCB0LCBuKSB7IGZvciAodmFyIHIgPSAwLCBpID0gdC5sZW5ndGg7IHIgPCBpOyByKyspb2UoZSwgdFtyXSwgbik7IHJldHVybiBuIH0gZnVuY3Rpb24gd2UoZSwgdCwgbiwgciwgaSkgeyBmb3IgKHZhciBvLCBhID0gW10sIHUgPSAwLCBzID0gZS5sZW5ndGgsIGwgPSBudWxsICE9IHQ7IHUgPCBzOyB1KyspKG8gPSBlW3VdKSAmJiAobiAmJiAhbihvLCByLCBpKSB8fCAoYS5wdXNoKG8pLCBsICYmIHQucHVzaCh1KSkpOyByZXR1cm4gYSB9IGZ1bmN0aW9uIENlKGUsIHQsIG4sIHIsIGksIG8pIHsgcmV0dXJuIHIgJiYgIXJbeF0gJiYgKHIgPSBDZShyKSksIGkgJiYgIWlbeF0gJiYgKGkgPSBDZShpLCBvKSksIHVlKGZ1bmN0aW9uIChvLCBhLCB1LCBzKSB7IHZhciBsLCBjLCBmLCBkID0gW10sIHAgPSBbXSwgaCA9IGEubGVuZ3RoLCBnID0gbyB8fCB4ZSh0IHx8ICIqIiwgdS5ub2RlVHlwZSA/IFt1XSA6IHUsIFtdKSwgdiA9ICFlIHx8ICFvICYmIHQgPyBnIDogd2UoZywgZCwgZSwgdSwgcyksIHkgPSBuID8gaSB8fCAobyA/IGUgOiBoIHx8IHIpID8gW10gOiBhIDogdjsgaWYgKG4gJiYgbih2LCB5LCB1LCBzKSwgcikgeyBsID0gd2UoeSwgcCksIHIobCwgW10sIHUsIHMpLCBjID0gbC5sZW5ndGg7IHdoaWxlIChjLS0pIChmID0gbFtjXSkgJiYgKHlbcFtjXV0gPSAhKHZbcFtjXV0gPSBmKSkgfSBpZiAobykgeyBpZiAoaSB8fCBlKSB7IGlmIChpKSB7IGwgPSBbXSwgYyA9IHkubGVuZ3RoOyB3aGlsZSAoYy0tKSAoZiA9IHlbY10pICYmIGwucHVzaCh2W2NdID0gZik7IGkobnVsbCwgeSA9IFtdLCBsLCBzKSB9IGMgPSB5Lmxlbmd0aDsgd2hpbGUgKGMtLSkgKGYgPSB5W2NdKSAmJiAobCA9IGkgPyBQKG8sIGYpIDogZFtjXSkgPiAtMSAmJiAob1tsXSA9ICEoYVtsXSA9IGYpKSB9IH0gZWxzZSB5ID0gd2UoeSA9PT0gYSA/IHkuc3BsaWNlKGgsIHkubGVuZ3RoKSA6IHkpLCBpID8gaShudWxsLCBhLCB5LCBzKSA6IHEuYXBwbHkoYSwgeSkgfSkgfSBmdW5jdGlvbiBUZShlKSB7IGZvciAodmFyIHQsIG4sIGksIG8gPSBlLmxlbmd0aCwgYSA9IHIucmVsYXRpdmVbZVswXS50eXBlXSwgdSA9IGEgfHwgci5yZWxhdGl2ZVsiICJdLCBzID0gYSA/IDEgOiAwLCBjID0gbWUoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUgPT09IHQgfSwgdSwgITApLCBmID0gbWUoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIFAodCwgZSkgPiAtMSB9LCB1LCAhMCksIGQgPSBbZnVuY3Rpb24gKGUsIG4sIHIpIHsgdmFyIGkgPSAhYSAmJiAociB8fCBuICE9PSBsKSB8fCAoKHQgPSBuKS5ub2RlVHlwZSA/IGMoZSwgbiwgcikgOiBmKGUsIG4sIHIpKTsgcmV0dXJuIHQgPSBudWxsLCBpIH1dOyBzIDwgbzsgcysrKWlmIChuID0gci5yZWxhdGl2ZVtlW3NdLnR5cGVdKSBkID0gW21lKGJlKGQpLCBuKV07IGVsc2UgeyBpZiAoKG4gPSByLmZpbHRlcltlW3NdLnR5cGVdLmFwcGx5KG51bGwsIGVbc10ubWF0Y2hlcykpW3hdKSB7IGZvciAoaSA9ICsrczsgaSA8IG87IGkrKylpZiAoci5yZWxhdGl2ZVtlW2ldLnR5cGVdKSBicmVhazsgcmV0dXJuIENlKHMgPiAxICYmIGJlKGQpLCBzID4gMSAmJiB5ZShlLnNsaWNlKDAsIHMgLSAxKS5jb25jYXQoeyB2YWx1ZTogIiAiID09PSBlW3MgLSAyXS50eXBlID8gIioiIDogIiIgfSkpLnJlcGxhY2UoJCwgIiQxIiksIG4sIHMgPCBpICYmIFRlKGUuc2xpY2UocywgaSkpLCBpIDwgbyAmJiBUZShlID0gZS5zbGljZShpKSksIGkgPCBvICYmIHllKGUpKSB9IGQucHVzaChuKSB9IHJldHVybiBiZShkKSB9IGZ1bmN0aW9uIEVlKGUsIHQpIHsgdmFyIG4gPSB0Lmxlbmd0aCA+IDAsIGkgPSBlLmxlbmd0aCA+IDAsIG8gPSBmdW5jdGlvbiAobywgYSwgdSwgcywgYykgeyB2YXIgZiwgaCwgdiwgeSA9IDAsIG0gPSAiMCIsIGIgPSBvICYmIFtdLCB4ID0gW10sIHcgPSBsLCBUID0gbyB8fCBpICYmIHIuZmluZC5UQUcoIioiLCBjKSwgRSA9IEMgKz0gbnVsbCA9PSB3ID8gMSA6IE1hdGgucmFuZG9tKCkgfHwgLjEsIE4gPSBULmxlbmd0aDsgZm9yIChjICYmIChsID0gYSA9PT0gcCB8fCBhIHx8IGMpOyBtICE9PSBOICYmIG51bGwgIT0gKGYgPSBUW21dKTsgbSsrKSB7IGlmIChpICYmIGYpIHsgaCA9IDAsIGEgfHwgZi5vd25lckRvY3VtZW50ID09PSBwIHx8IChkKGYpLCB1ID0gIWcpOyB3aGlsZSAodiA9IGVbaCsrXSkgaWYgKHYoZiwgYSB8fCBwLCB1KSkgeyBzLnB1c2goZik7IGJyZWFrIH0gYyAmJiAoQyA9IEUpIH0gbiAmJiAoKGYgPSAhdiAmJiBmKSAmJiB5LS0gLCBvICYmIGIucHVzaChmKSkgfSBpZiAoeSArPSBtLCBuICYmIG0gIT09IHkpIHsgaCA9IDA7IHdoaWxlICh2ID0gdFtoKytdKSB2KGIsIHgsIGEsIHUpOyBpZiAobykgeyBpZiAoeSA+IDApIHdoaWxlIChtLS0pIGJbbV0gfHwgeFttXSB8fCAoeFttXSA9IEwuY2FsbChzKSk7IHggPSB3ZSh4KSB9IHEuYXBwbHkocywgeCksIGMgJiYgIW8gJiYgeC5sZW5ndGggPiAwICYmIHkgKyB0Lmxlbmd0aCA+IDEgJiYgb2UudW5pcXVlU29ydChzKSB9IHJldHVybiBjICYmIChDID0gRSwgbCA9IHcpLCBiIH07IHJldHVybiBuID8gdWUobykgOiBvIH0gcmV0dXJuIHUgPSBvZS5jb21waWxlID0gZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIgPSBbXSwgaSA9IFtdLCBvID0ga1tlICsgIiAiXTsgaWYgKCFvKSB7IHQgfHwgKHQgPSBhKGUpKSwgbiA9IHQubGVuZ3RoOyB3aGlsZSAobi0tKSAobyA9IFRlKHRbbl0pKVt4XSA/IHIucHVzaChvKSA6IGkucHVzaChvKTsgKG8gPSBrKGUsIEVlKGksIHIpKSkuc2VsZWN0b3IgPSBlIH0gcmV0dXJuIG8gfSwgcyA9IG9lLnNlbGVjdCA9IGZ1bmN0aW9uIChlLCB0LCBuLCBpKSB7IHZhciBvLCBzLCBsLCBjLCBmLCBkID0gImZ1bmN0aW9uIiA9PSB0eXBlb2YgZSAmJiBlLCBwID0gIWkgJiYgYShlID0gZC5zZWxlY3RvciB8fCBlKTsgaWYgKG4gPSBuIHx8IFtdLCAxID09PSBwLmxlbmd0aCkgeyBpZiAoKHMgPSBwWzBdID0gcFswXS5zbGljZSgwKSkubGVuZ3RoID4gMiAmJiAiSUQiID09PSAobCA9IHNbMF0pLnR5cGUgJiYgOSA9PT0gdC5ub2RlVHlwZSAmJiBnICYmIHIucmVsYXRpdmVbc1sxXS50eXBlXSkgeyBpZiAoISh0ID0gKHIuZmluZC5JRChsLm1hdGNoZXNbMF0ucmVwbGFjZShaLCBlZSksIHQpIHx8IFtdKVswXSkpIHJldHVybiBuOyBkICYmICh0ID0gdC5wYXJlbnROb2RlKSwgZSA9IGUuc2xpY2Uocy5zaGlmdCgpLnZhbHVlLmxlbmd0aCkgfSBvID0gWC5uZWVkc0NvbnRleHQudGVzdChlKSA/IDAgOiBzLmxlbmd0aDsgd2hpbGUgKG8tLSkgeyBpZiAobCA9IHNbb10sIHIucmVsYXRpdmVbYyA9IGwudHlwZV0pIGJyZWFrOyBpZiAoKGYgPSByLmZpbmRbY10pICYmIChpID0gZihsLm1hdGNoZXNbMF0ucmVwbGFjZShaLCBlZSksIEoudGVzdChzWzBdLnR5cGUpICYmIGdlKHQucGFyZW50Tm9kZSkgfHwgdCkpKSB7IGlmIChzLnNwbGljZShvLCAxKSwgIShlID0gaS5sZW5ndGggJiYgeWUocykpKSByZXR1cm4gcS5hcHBseShuLCBpKSwgbjsgYnJlYWsgfSB9IH0gcmV0dXJuIChkIHx8IHUoZSwgcCkpKGksIHQsICFnLCBuLCAhdCB8fCBKLnRlc3QoZSkgJiYgZ2UodC5wYXJlbnROb2RlKSB8fCB0KSwgbiB9LCBuLnNvcnRTdGFibGUgPSB4LnNwbGl0KCIiKS5zb3J0KEEpLmpvaW4oIiIpID09PSB4LCBuLmRldGVjdER1cGxpY2F0ZXMgPSAhIWYsIGQoKSwgbi5zb3J0RGV0YWNoZWQgPSBzZShmdW5jdGlvbiAoZSkgeyByZXR1cm4gMSAmIGUuY29tcGFyZURvY3VtZW50UG9zaXRpb24ocC5jcmVhdGVFbGVtZW50KCJmaWVsZHNldCIpKSB9KSwgc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUuaW5uZXJIVE1MID0gIjxhIGhyZWY9JyMnPjwvYT4iLCAiIyIgPT09IGUuZmlyc3RDaGlsZC5nZXRBdHRyaWJ1dGUoImhyZWYiKSB9KSB8fCBsZSgidHlwZXxocmVmfGhlaWdodHx3aWR0aCIsIGZ1bmN0aW9uIChlLCB0LCBuKSB7IGlmICghbikgcmV0dXJuIGUuZ2V0QXR0cmlidXRlKHQsICJ0eXBlIiA9PT0gdC50b0xvd2VyQ2FzZSgpID8gMSA6IDIpIH0pLCBuLmF0dHJpYnV0ZXMgJiYgc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUuaW5uZXJIVE1MID0gIjxpbnB1dC8+IiwgZS5maXJzdENoaWxkLnNldEF0dHJpYnV0ZSgidmFsdWUiLCAiIiksICIiID09PSBlLmZpcnN0Q2hpbGQuZ2V0QXR0cmlidXRlKCJ2YWx1ZSIpIH0pIHx8IGxlKCJ2YWx1ZSIsIGZ1bmN0aW9uIChlLCB0LCBuKSB7IGlmICghbiAmJiAiaW5wdXQiID09PSBlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkpIHJldHVybiBlLmRlZmF1bHRWYWx1ZSB9KSwgc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIG51bGwgPT0gZS5nZXRBdHRyaWJ1dGUoImRpc2FibGVkIikgfSkgfHwgbGUoSCwgZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHI7IGlmICghbikgcmV0dXJuICEwID09PSBlW3RdID8gdC50b0xvd2VyQ2FzZSgpIDogKHIgPSBlLmdldEF0dHJpYnV0ZU5vZGUodCkpICYmIHIuc3BlY2lmaWVkID8gci52YWx1ZSA6IG51bGwgfSksIG9lIH0oZSk7IHcuZmluZCA9IEUsIHcuZXhwciA9IEUuc2VsZWN0b3JzLCB3LmV4cHJbIjoiXSA9IHcuZXhwci5wc2V1ZG9zLCB3LnVuaXF1ZVNvcnQgPSB3LnVuaXF1ZSA9IEUudW5pcXVlU29ydCwgdy50ZXh0ID0gRS5nZXRUZXh0LCB3LmlzWE1MRG9jID0gRS5pc1hNTCwgdy5jb250YWlucyA9IEUuY29udGFpbnMsIHcuZXNjYXBlU2VsZWN0b3IgPSBFLmVzY2FwZTsgdmFyIE4gPSBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciA9IFtdLCBpID0gdm9pZCAwICE9PSBuOyB3aGlsZSAoKGUgPSBlW3RdKSAmJiA5ICE9PSBlLm5vZGVUeXBlKSBpZiAoMSA9PT0gZS5ub2RlVHlwZSkgeyBpZiAoaSAmJiB3KGUpLmlzKG4pKSBicmVhazsgci5wdXNoKGUpIH0gcmV0dXJuIHIgfSwgayA9IGZ1bmN0aW9uIChlLCB0KSB7IGZvciAodmFyIG4gPSBbXTsgZTsgZSA9IGUubmV4dFNpYmxpbmcpMSA9PT0gZS5ub2RlVHlwZSAmJiBlICE9PSB0ICYmIG4ucHVzaChlKTsgcmV0dXJuIG4gfSwgQSA9IHcuZXhwci5tYXRjaC5uZWVkc0NvbnRleHQ7IGZ1bmN0aW9uIEQoZSwgdCkgeyByZXR1cm4gZS5ub2RlTmFtZSAmJiBlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IHQudG9Mb3dlckNhc2UoKSB9IHZhciBTID0gL148KFthLXpdW15cL1wwPjpceDIwXHRcclxuXGZdKilbXHgyMFx0XHJcblxmXSpcLz8+KD86PFwvXDE+fCkkL2k7IGZ1bmN0aW9uIEwoZSwgdCwgbikgeyByZXR1cm4gZyh0KSA/IHcuZ3JlcChlLCBmdW5jdGlvbiAoZSwgcikgeyByZXR1cm4gISF0LmNhbGwoZSwgciwgZSkgIT09IG4gfSkgOiB0Lm5vZGVUeXBlID8gdy5ncmVwKGUsIGZ1bmN0aW9uIChlKSB7IHJldHVybiBlID09PSB0ICE9PSBuIH0pIDogInN0cmluZyIgIT0gdHlwZW9mIHQgPyB3LmdyZXAoZSwgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHMuY2FsbCh0LCBlKSA+IC0xICE9PSBuIH0pIDogdy5maWx0ZXIodCwgZSwgbikgfSB3LmZpbHRlciA9IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHZhciByID0gdFswXTsgcmV0dXJuIG4gJiYgKGUgPSAiOm5vdCgiICsgZSArICIpIiksIDEgPT09IHQubGVuZ3RoICYmIDEgPT09IHIubm9kZVR5cGUgPyB3LmZpbmQubWF0Y2hlc1NlbGVjdG9yKHIsIGUpID8gW3JdIDogW10gOiB3LmZpbmQubWF0Y2hlcyhlLCB3LmdyZXAodCwgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIDEgPT09IGUubm9kZVR5cGUgfSkpIH0sIHcuZm4uZXh0ZW5kKHsgZmluZDogZnVuY3Rpb24gKGUpIHsgdmFyIHQsIG4sIHIgPSB0aGlzLmxlbmd0aCwgaSA9IHRoaXM7IGlmICgic3RyaW5nIiAhPSB0eXBlb2YgZSkgcmV0dXJuIHRoaXMucHVzaFN0YWNrKHcoZSkuZmlsdGVyKGZ1bmN0aW9uICgpIHsgZm9yICh0ID0gMDsgdCA8IHI7IHQrKylpZiAody5jb250YWlucyhpW3RdLCB0aGlzKSkgcmV0dXJuICEwIH0pKTsgZm9yIChuID0gdGhpcy5wdXNoU3RhY2soW10pLCB0ID0gMDsgdCA8IHI7IHQrKyl3LmZpbmQoZSwgaVt0XSwgbik7IHJldHVybiByID4gMSA/IHcudW5pcXVlU29ydChuKSA6IG4gfSwgZmlsdGVyOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5wdXNoU3RhY2soTCh0aGlzLCBlIHx8IFtdLCAhMSkpIH0sIG5vdDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHRoaXMucHVzaFN0YWNrKEwodGhpcywgZSB8fCBbXSwgITApKSB9LCBpczogZnVuY3Rpb24gKGUpIHsgcmV0dXJuICEhTCh0aGlzLCAic3RyaW5nIiA9PSB0eXBlb2YgZSAmJiBBLnRlc3QoZSkgPyB3KGUpIDogZSB8fCBbXSwgITEpLmxlbmd0aCB9IH0pOyB2YXIgaiwgcSA9IC9eKD86XHMqKDxbXHdcV10rPilbXj5dKnwjKFtcdy1dKykpJC87ICh3LmZuLmluaXQgPSBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgaSwgbzsgaWYgKCFlKSByZXR1cm4gdGhpczsgaWYgKG4gPSBuIHx8IGosICJzdHJpbmciID09IHR5cGVvZiBlKSB7IGlmICghKGkgPSAiPCIgPT09IGVbMF0gJiYgIj4iID09PSBlW2UubGVuZ3RoIC0gMV0gJiYgZS5sZW5ndGggPj0gMyA/IFtudWxsLCBlLCBudWxsXSA6IHEuZXhlYyhlKSkgfHwgIWlbMV0gJiYgdCkgcmV0dXJuICF0IHx8IHQuanF1ZXJ5ID8gKHQgfHwgbikuZmluZChlKSA6IHRoaXMuY29uc3RydWN0b3IodCkuZmluZChlKTsgaWYgKGlbMV0pIHsgaWYgKHQgPSB0IGluc3RhbmNlb2YgdyA/IHRbMF0gOiB0LCB3Lm1lcmdlKHRoaXMsIHcucGFyc2VIVE1MKGlbMV0sIHQgJiYgdC5ub2RlVHlwZSA/IHQub3duZXJEb2N1bWVudCB8fCB0IDogciwgITApKSwgUy50ZXN0KGlbMV0pICYmIHcuaXNQbGFpbk9iamVjdCh0KSkgZm9yIChpIGluIHQpIGcodGhpc1tpXSkgPyB0aGlzW2ldKHRbaV0pIDogdGhpcy5hdHRyKGksIHRbaV0pOyByZXR1cm4gdGhpcyB9IHJldHVybiAobyA9IHIuZ2V0RWxlbWVudEJ5SWQoaVsyXSkpICYmICh0aGlzWzBdID0gbywgdGhpcy5sZW5ndGggPSAxKSwgdGhpcyB9IHJldHVybiBlLm5vZGVUeXBlID8gKHRoaXNbMF0gPSBlLCB0aGlzLmxlbmd0aCA9IDEsIHRoaXMpIDogZyhlKSA/IHZvaWQgMCAhPT0gbi5yZWFkeSA/IG4ucmVhZHkoZSkgOiBlKHcpIDogdy5tYWtlQXJyYXkoZSwgdGhpcykgfSkucHJvdG90eXBlID0gdy5mbiwgaiA9IHcocik7IHZhciBPID0gL14oPzpwYXJlbnRzfHByZXYoPzpVbnRpbHxBbGwpKS8sIFAgPSB7IGNoaWxkcmVuOiAhMCwgY29udGVudHM6ICEwLCBuZXh0OiAhMCwgcHJldjogITAgfTsgdy5mbi5leHRlbmQoeyBoYXM6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gdyhlLCB0aGlzKSwgbiA9IHQubGVuZ3RoOyByZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24gKCkgeyBmb3IgKHZhciBlID0gMDsgZSA8IG47IGUrKylpZiAody5jb250YWlucyh0aGlzLCB0W2VdKSkgcmV0dXJuICEwIH0pIH0sIGNsb3Nlc3Q6IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCByID0gMCwgaSA9IHRoaXMubGVuZ3RoLCBvID0gW10sIGEgPSAic3RyaW5nIiAhPSB0eXBlb2YgZSAmJiB3KGUpOyBpZiAoIUEudGVzdChlKSkgZm9yICg7IHIgPCBpOyByKyspZm9yIChuID0gdGhpc1tyXTsgbiAmJiBuICE9PSB0OyBuID0gbi5wYXJlbnROb2RlKWlmIChuLm5vZGVUeXBlIDwgMTEgJiYgKGEgPyBhLmluZGV4KG4pID4gLTEgOiAxID09PSBuLm5vZGVUeXBlICYmIHcuZmluZC5tYXRjaGVzU2VsZWN0b3IobiwgZSkpKSB7IG8ucHVzaChuKTsgYnJlYWsgfSByZXR1cm4gdGhpcy5wdXNoU3RhY2soby5sZW5ndGggPiAxID8gdy51bmlxdWVTb3J0KG8pIDogbykgfSwgaW5kZXg6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBlID8gInN0cmluZyIgPT0gdHlwZW9mIGUgPyBzLmNhbGwodyhlKSwgdGhpc1swXSkgOiBzLmNhbGwodGhpcywgZS5qcXVlcnkgPyBlWzBdIDogZSkgOiB0aGlzWzBdICYmIHRoaXNbMF0ucGFyZW50Tm9kZSA/IHRoaXMuZmlyc3QoKS5wcmV2QWxsKCkubGVuZ3RoIDogLTEgfSwgYWRkOiBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gdGhpcy5wdXNoU3RhY2sody51bmlxdWVTb3J0KHcubWVyZ2UodGhpcy5nZXQoKSwgdyhlLCB0KSkpKSB9LCBhZGRCYWNrOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5hZGQobnVsbCA9PSBlID8gdGhpcy5wcmV2T2JqZWN0IDogdGhpcy5wcmV2T2JqZWN0LmZpbHRlcihlKSkgfSB9KTsgZnVuY3Rpb24gSChlLCB0KSB7IHdoaWxlICgoZSA9IGVbdF0pICYmIDEgIT09IGUubm9kZVR5cGUpOyByZXR1cm4gZSB9IHcuZWFjaCh7IHBhcmVudDogZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSBlLnBhcmVudE5vZGU7IHJldHVybiB0ICYmIDExICE9PSB0Lm5vZGVUeXBlID8gdCA6IG51bGwgfSwgcGFyZW50czogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIE4oZSwgInBhcmVudE5vZGUiKSB9LCBwYXJlbnRzVW50aWw6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBOKGUsICJwYXJlbnROb2RlIiwgbikgfSwgbmV4dDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEgoZSwgIm5leHRTaWJsaW5nIikgfSwgcHJldjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEgoZSwgInByZXZpb3VzU2libGluZyIpIH0sIG5leHRBbGw6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBOKGUsICJuZXh0U2libGluZyIpIH0sIHByZXZBbGw6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBOKGUsICJwcmV2aW91c1NpYmxpbmciKSB9LCBuZXh0VW50aWw6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBOKGUsICJuZXh0U2libGluZyIsIG4pIH0sIHByZXZVbnRpbDogZnVuY3Rpb24gKGUsIHQsIG4pIHsgcmV0dXJuIE4oZSwgInByZXZpb3VzU2libGluZyIsIG4pIH0sIHNpYmxpbmdzOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gaygoZS5wYXJlbnROb2RlIHx8IHt9KS5maXJzdENoaWxkLCBlKSB9LCBjaGlsZHJlbjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGsoZS5maXJzdENoaWxkKSB9LCBjb250ZW50czogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEQoZSwgImlmcmFtZSIpID8gZS5jb250ZW50RG9jdW1lbnQgOiAoRChlLCAidGVtcGxhdGUiKSAmJiAoZSA9IGUuY29udGVudCB8fCBlKSwgdy5tZXJnZShbXSwgZS5jaGlsZE5vZGVzKSkgfSB9LCBmdW5jdGlvbiAoZSwgdCkgeyB3LmZuW2VdID0gZnVuY3Rpb24gKG4sIHIpIHsgdmFyIGkgPSB3Lm1hcCh0aGlzLCB0LCBuKTsgcmV0dXJuICJVbnRpbCIgIT09IGUuc2xpY2UoLTUpICYmIChyID0gbiksIHIgJiYgInN0cmluZyIgPT0gdHlwZW9mIHIgJiYgKGkgPSB3LmZpbHRlcihyLCBpKSksIHRoaXMubGVuZ3RoID4gMSAmJiAoUFtlXSB8fCB3LnVuaXF1ZVNvcnQoaSksIE8udGVzdChlKSAmJiBpLnJldmVyc2UoKSksIHRoaXMucHVzaFN0YWNrKGkpIH0gfSk7IHZhciBJID0gL1teXHgyMFx0XHJcblxmXSsvZzsgZnVuY3Rpb24gUihlKSB7IHZhciB0ID0ge307IHJldHVybiB3LmVhY2goZS5tYXRjaChJKSB8fCBbXSwgZnVuY3Rpb24gKGUsIG4pIHsgdFtuXSA9ICEwIH0pLCB0IH0gdy5DYWxsYmFja3MgPSBmdW5jdGlvbiAoZSkgeyBlID0gInN0cmluZyIgPT0gdHlwZW9mIGUgPyBSKGUpIDogdy5leHRlbmQoe30sIGUpOyB2YXIgdCwgbiwgciwgaSwgbyA9IFtdLCBhID0gW10sIHUgPSAtMSwgcyA9IGZ1bmN0aW9uICgpIHsgZm9yIChpID0gaSB8fCBlLm9uY2UsIHIgPSB0ID0gITA7IGEubGVuZ3RoOyB1ID0gLTEpIHsgbiA9IGEuc2hpZnQoKTsgd2hpbGUgKCsrdSA8IG8ubGVuZ3RoKSAhMSA9PT0gb1t1XS5hcHBseShuWzBdLCBuWzFdKSAmJiBlLnN0b3BPbkZhbHNlICYmICh1ID0gby5sZW5ndGgsIG4gPSAhMSkgfSBlLm1lbW9yeSB8fCAobiA9ICExKSwgdCA9ICExLCBpICYmIChvID0gbiA/IFtdIDogIiIpIH0sIGwgPSB7IGFkZDogZnVuY3Rpb24gKCkgeyByZXR1cm4gbyAmJiAobiAmJiAhdCAmJiAodSA9IG8ubGVuZ3RoIC0gMSwgYS5wdXNoKG4pKSwgZnVuY3Rpb24gdChuKSB7IHcuZWFjaChuLCBmdW5jdGlvbiAobiwgcikgeyBnKHIpID8gZS51bmlxdWUgJiYgbC5oYXMocikgfHwgby5wdXNoKHIpIDogciAmJiByLmxlbmd0aCAmJiAic3RyaW5nIiAhPT0gYihyKSAmJiB0KHIpIH0pIH0oYXJndW1lbnRzKSwgbiAmJiAhdCAmJiBzKCkpLCB0aGlzIH0sIHJlbW92ZTogZnVuY3Rpb24gKCkgeyByZXR1cm4gdy5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG47IHdoaWxlICgobiA9IHcuaW5BcnJheSh0LCBvLCBuKSkgPiAtMSkgby5zcGxpY2UobiwgMSksIG4gPD0gdSAmJiB1LS0gfSksIHRoaXMgfSwgaGFzOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZSA/IHcuaW5BcnJheShlLCBvKSA+IC0xIDogby5sZW5ndGggPiAwIH0sIGVtcHR5OiBmdW5jdGlvbiAoKSB7IHJldHVybiBvICYmIChvID0gW10pLCB0aGlzIH0sIGRpc2FibGU6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGkgPSBhID0gW10sIG8gPSBuID0gIiIsIHRoaXMgfSwgZGlzYWJsZWQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuICFvIH0sIGxvY2s6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGkgPSBhID0gW10sIG4gfHwgdCB8fCAobyA9IG4gPSAiIiksIHRoaXMgfSwgbG9ja2VkOiBmdW5jdGlvbiAoKSB7IHJldHVybiAhIWkgfSwgZmlyZVdpdGg6IGZ1bmN0aW9uIChlLCBuKSB7IHJldHVybiBpIHx8IChuID0gW2UsIChuID0gbiB8fCBbXSkuc2xpY2UgPyBuLnNsaWNlKCkgOiBuXSwgYS5wdXNoKG4pLCB0IHx8IHMoKSksIHRoaXMgfSwgZmlyZTogZnVuY3Rpb24gKCkgeyByZXR1cm4gbC5maXJlV2l0aCh0aGlzLCBhcmd1bWVudHMpLCB0aGlzIH0sIGZpcmVkOiBmdW5jdGlvbiAoKSB7IHJldHVybiAhIXIgfSB9OyByZXR1cm4gbCB9OyBmdW5jdGlvbiBCKGUpIHsgcmV0dXJuIGUgfSBmdW5jdGlvbiBNKGUpIHsgdGhyb3cgZSB9IGZ1bmN0aW9uIFcoZSwgdCwgbiwgcikgeyB2YXIgaTsgdHJ5IHsgZSAmJiBnKGkgPSBlLnByb21pc2UpID8gaS5jYWxsKGUpLmRvbmUodCkuZmFpbChuKSA6IGUgJiYgZyhpID0gZS50aGVuKSA/IGkuY2FsbChlLCB0LCBuKSA6IHQuYXBwbHkodm9pZCAwLCBbZV0uc2xpY2UocikpIH0gY2F0Y2ggKGUpIHsgbi5hcHBseSh2b2lkIDAsIFtlXSkgfSB9IHcuZXh0ZW5kKHsgRGVmZXJyZWQ6IGZ1bmN0aW9uICh0KSB7IHZhciBuID0gW1sibm90aWZ5IiwgInByb2dyZXNzIiwgdy5DYWxsYmFja3MoIm1lbW9yeSIpLCB3LkNhbGxiYWNrcygibWVtb3J5IiksIDJdLCBbInJlc29sdmUiLCAiZG9uZSIsIHcuQ2FsbGJhY2tzKCJvbmNlIG1lbW9yeSIpLCB3LkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSwgMCwgInJlc29sdmVkIl0sIFsicmVqZWN0IiwgImZhaWwiLCB3LkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSwgdy5DYWxsYmFja3MoIm9uY2UgbWVtb3J5IiksIDEsICJyZWplY3RlZCJdXSwgciA9ICJwZW5kaW5nIiwgaSA9IHsgc3RhdGU6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHIgfSwgYWx3YXlzOiBmdW5jdGlvbiAoKSB7IHJldHVybiBvLmRvbmUoYXJndW1lbnRzKS5mYWlsKGFyZ3VtZW50cyksIHRoaXMgfSwgImNhdGNoIjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGkudGhlbihudWxsLCBlKSB9LCBwaXBlOiBmdW5jdGlvbiAoKSB7IHZhciBlID0gYXJndW1lbnRzOyByZXR1cm4gdy5EZWZlcnJlZChmdW5jdGlvbiAodCkgeyB3LmVhY2gobiwgZnVuY3Rpb24gKG4sIHIpIHsgdmFyIGkgPSBnKGVbcls0XV0pICYmIGVbcls0XV07IG9bclsxXV0oZnVuY3Rpb24gKCkgeyB2YXIgZSA9IGkgJiYgaS5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyBlICYmIGcoZS5wcm9taXNlKSA/IGUucHJvbWlzZSgpLnByb2dyZXNzKHQubm90aWZ5KS5kb25lKHQucmVzb2x2ZSkuZmFpbCh0LnJlamVjdCkgOiB0W3JbMF0gKyAiV2l0aCJdKHRoaXMsIGkgPyBbZV0gOiBhcmd1bWVudHMpIH0pIH0pLCBlID0gbnVsbCB9KS5wcm9taXNlKCkgfSwgdGhlbjogZnVuY3Rpb24gKHQsIHIsIGkpIHsgdmFyIG8gPSAwOyBmdW5jdGlvbiBhKHQsIG4sIHIsIGkpIHsgcmV0dXJuIGZ1bmN0aW9uICgpIHsgdmFyIHUgPSB0aGlzLCBzID0gYXJndW1lbnRzLCBsID0gZnVuY3Rpb24gKCkgeyB2YXIgZSwgbDsgaWYgKCEodCA8IG8pKSB7IGlmICgoZSA9IHIuYXBwbHkodSwgcykpID09PSBuLnByb21pc2UoKSkgdGhyb3cgbmV3IFR5cGVFcnJvcigiVGhlbmFibGUgc2VsZi1yZXNvbHV0aW9uIik7IGwgPSBlICYmICgib2JqZWN0IiA9PSB0eXBlb2YgZSB8fCAiZnVuY3Rpb24iID09IHR5cGVvZiBlKSAmJiBlLnRoZW4sIGcobCkgPyBpID8gbC5jYWxsKGUsIGEobywgbiwgQiwgaSksIGEobywgbiwgTSwgaSkpIDogKG8rKyAsIGwuY2FsbChlLCBhKG8sIG4sIEIsIGkpLCBhKG8sIG4sIE0sIGkpLCBhKG8sIG4sIEIsIG4ubm90aWZ5V2l0aCkpKSA6IChyICE9PSBCICYmICh1ID0gdm9pZCAwLCBzID0gW2VdKSwgKGkgfHwgbi5yZXNvbHZlV2l0aCkodSwgcykpIH0gfSwgYyA9IGkgPyBsIDogZnVuY3Rpb24gKCkgeyB0cnkgeyBsKCkgfSBjYXRjaCAoZSkgeyB3LkRlZmVycmVkLmV4Y2VwdGlvbkhvb2sgJiYgdy5EZWZlcnJlZC5leGNlcHRpb25Ib29rKGUsIGMuc3RhY2tUcmFjZSksIHQgKyAxID49IG8gJiYgKHIgIT09IE0gJiYgKHUgPSB2b2lkIDAsIHMgPSBbZV0pLCBuLnJlamVjdFdpdGgodSwgcykpIH0gfTsgdCA/IGMoKSA6ICh3LkRlZmVycmVkLmdldFN0YWNrSG9vayAmJiAoYy5zdGFja1RyYWNlID0gdy5EZWZlcnJlZC5nZXRTdGFja0hvb2soKSksIGUuc2V0VGltZW91dChjKSkgfSB9IHJldHVybiB3LkRlZmVycmVkKGZ1bmN0aW9uIChlKSB7IG5bMF1bM10uYWRkKGEoMCwgZSwgZyhpKSA/IGkgOiBCLCBlLm5vdGlmeVdpdGgpKSwgblsxXVszXS5hZGQoYSgwLCBlLCBnKHQpID8gdCA6IEIpKSwgblsyXVszXS5hZGQoYSgwLCBlLCBnKHIpID8gciA6IE0pKSB9KS5wcm9taXNlKCkgfSwgcHJvbWlzZTogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIG51bGwgIT0gZSA/IHcuZXh0ZW5kKGUsIGkpIDogaSB9IH0sIG8gPSB7fTsgcmV0dXJuIHcuZWFjaChuLCBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgYSA9IHRbMl0sIHUgPSB0WzVdOyBpW3RbMV1dID0gYS5hZGQsIHUgJiYgYS5hZGQoZnVuY3Rpb24gKCkgeyByID0gdSB9LCBuWzMgLSBlXVsyXS5kaXNhYmxlLCBuWzMgLSBlXVszXS5kaXNhYmxlLCBuWzBdWzJdLmxvY2ssIG5bMF1bM10ubG9jayksIGEuYWRkKHRbM10uZmlyZSksIG9bdFswXV0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiBvW3RbMF0gKyAiV2l0aCJdKHRoaXMgPT09IG8gPyB2b2lkIDAgOiB0aGlzLCBhcmd1bWVudHMpLCB0aGlzIH0sIG9bdFswXSArICJXaXRoIl0gPSBhLmZpcmVXaXRoIH0pLCBpLnByb21pc2UobyksIHQgJiYgdC5jYWxsKG8sIG8pLCBvIH0sIHdoZW46IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gYXJndW1lbnRzLmxlbmd0aCwgbiA9IHQsIHIgPSBBcnJheShuKSwgaSA9IG8uY2FsbChhcmd1bWVudHMpLCBhID0gdy5EZWZlcnJlZCgpLCB1ID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGZ1bmN0aW9uIChuKSB7IHJbZV0gPSB0aGlzLCBpW2VdID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgPyBvLmNhbGwoYXJndW1lbnRzKSA6IG4sIC0tdCB8fCBhLnJlc29sdmVXaXRoKHIsIGkpIH0gfTsgaWYgKHQgPD0gMSAmJiAoVyhlLCBhLmRvbmUodShuKSkucmVzb2x2ZSwgYS5yZWplY3QsICF0KSwgInBlbmRpbmciID09PSBhLnN0YXRlKCkgfHwgZyhpW25dICYmIGlbbl0udGhlbikpKSByZXR1cm4gYS50aGVuKCk7IHdoaWxlIChuLS0pIFcoaVtuXSwgdShuKSwgYS5yZWplY3QpOyByZXR1cm4gYS5wcm9taXNlKCkgfSB9KTsgdmFyICQgPSAvXihFdmFsfEludGVybmFsfFJhbmdlfFJlZmVyZW5jZXxTeW50YXh8VHlwZXxVUkkpRXJyb3IkLzsgdy5EZWZlcnJlZC5leGNlcHRpb25Ib29rID0gZnVuY3Rpb24gKHQsIG4pIHsgZS5jb25zb2xlICYmIGUuY29uc29sZS53YXJuICYmIHQgJiYgJC50ZXN0KHQubmFtZSkgJiYgZS5jb25zb2xlLndhcm4oImpRdWVyeS5EZWZlcnJlZCBleGNlcHRpb246ICIgKyB0Lm1lc3NhZ2UsIHQuc3RhY2ssIG4pIH0sIHcucmVhZHlFeGNlcHRpb24gPSBmdW5jdGlvbiAodCkgeyBlLnNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyB0aHJvdyB0IH0pIH07IHZhciBGID0gdy5EZWZlcnJlZCgpOyB3LmZuLnJlYWR5ID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEYudGhlbihlKVsiY2F0Y2giXShmdW5jdGlvbiAoZSkgeyB3LnJlYWR5RXhjZXB0aW9uKGUpIH0pLCB0aGlzIH0sIHcuZXh0ZW5kKHsgaXNSZWFkeTogITEsIHJlYWR5V2FpdDogMSwgcmVhZHk6IGZ1bmN0aW9uIChlKSB7ICghMCA9PT0gZSA/IC0tdy5yZWFkeVdhaXQgOiB3LmlzUmVhZHkpIHx8ICh3LmlzUmVhZHkgPSAhMCwgITAgIT09IGUgJiYgLS13LnJlYWR5V2FpdCA+IDAgfHwgRi5yZXNvbHZlV2l0aChyLCBbd10pKSB9IH0pLCB3LnJlYWR5LnRoZW4gPSBGLnRoZW47IGZ1bmN0aW9uIHooKSB7IHIucmVtb3ZlRXZlbnRMaXN0ZW5lcigiRE9NQ29udGVudExvYWRlZCIsIHopLCBlLnJlbW92ZUV2ZW50TGlzdGVuZXIoImxvYWQiLCB6KSwgdy5yZWFkeSgpIH0gImNvbXBsZXRlIiA9PT0gci5yZWFkeVN0YXRlIHx8ICJsb2FkaW5nIiAhPT0gci5yZWFkeVN0YXRlICYmICFyLmRvY3VtZW50RWxlbWVudC5kb1Njcm9sbCA/IGUuc2V0VGltZW91dCh3LnJlYWR5KSA6IChyLmFkZEV2ZW50TGlzdGVuZXIoIkRPTUNvbnRlbnRMb2FkZWQiLCB6KSwgZS5hZGRFdmVudExpc3RlbmVyKCJsb2FkIiwgeikpOyB2YXIgXyA9IGZ1bmN0aW9uIChlLCB0LCBuLCByLCBpLCBvLCBhKSB7IHZhciB1ID0gMCwgcyA9IGUubGVuZ3RoLCBsID0gbnVsbCA9PSBuOyBpZiAoIm9iamVjdCIgPT09IGIobikpIHsgaSA9ICEwOyBmb3IgKHUgaW4gbikgXyhlLCB0LCB1LCBuW3VdLCAhMCwgbywgYSkgfSBlbHNlIGlmICh2b2lkIDAgIT09IHIgJiYgKGkgPSAhMCwgZyhyKSB8fCAoYSA9ICEwKSwgbCAmJiAoYSA/ICh0LmNhbGwoZSwgciksIHQgPSBudWxsKSA6IChsID0gdCwgdCA9IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBsLmNhbGwodyhlKSwgbikgfSkpLCB0KSkgZm9yICg7IHUgPCBzOyB1KyspdChlW3VdLCBuLCBhID8gciA6IHIuY2FsbChlW3VdLCB1LCB0KGVbdV0sIG4pKSk7IHJldHVybiBpID8gZSA6IGwgPyB0LmNhbGwoZSkgOiBzID8gdChlWzBdLCBuKSA6IG8gfSwgVSA9IC9eLW1zLS8sIFYgPSAvLShbYS16XSkvZzsgZnVuY3Rpb24gWChlLCB0KSB7IHJldHVybiB0LnRvVXBwZXJDYXNlKCkgfSBmdW5jdGlvbiBRKGUpIHsgcmV0dXJuIGUucmVwbGFjZShVLCAibXMtIikucmVwbGFjZShWLCBYKSB9IHZhciBZID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuIDEgPT09IGUubm9kZVR5cGUgfHwgOSA9PT0gZS5ub2RlVHlwZSB8fCAhK2Uubm9kZVR5cGUgfTsgZnVuY3Rpb24gRygpIHsgdGhpcy5leHBhbmRvID0gdy5leHBhbmRvICsgRy51aWQrKyB9IEcudWlkID0gMSwgRy5wcm90b3R5cGUgPSB7IGNhY2hlOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGVbdGhpcy5leHBhbmRvXTsgcmV0dXJuIHQgfHwgKHQgPSB7fSwgWShlKSAmJiAoZS5ub2RlVHlwZSA/IGVbdGhpcy5leHBhbmRvXSA9IHQgOiBPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwgdGhpcy5leHBhbmRvLCB7IHZhbHVlOiB0LCBjb25maWd1cmFibGU6ICEwIH0pKSksIHQgfSwgc2V0OiBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciwgaSA9IHRoaXMuY2FjaGUoZSk7IGlmICgic3RyaW5nIiA9PSB0eXBlb2YgdCkgaVtRKHQpXSA9IG47IGVsc2UgZm9yIChyIGluIHQpIGlbUShyKV0gPSB0W3JdOyByZXR1cm4gaSB9LCBnZXQ6IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiB2b2lkIDAgPT09IHQgPyB0aGlzLmNhY2hlKGUpIDogZVt0aGlzLmV4cGFuZG9dICYmIGVbdGhpcy5leHBhbmRvXVtRKHQpXSB9LCBhY2Nlc3M6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiB2b2lkIDAgPT09IHQgfHwgdCAmJiAic3RyaW5nIiA9PSB0eXBlb2YgdCAmJiB2b2lkIDAgPT09IG4gPyB0aGlzLmdldChlLCB0KSA6ICh0aGlzLnNldChlLCB0LCBuKSwgdm9pZCAwICE9PSBuID8gbiA6IHQpIH0sIHJlbW92ZTogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIgPSBlW3RoaXMuZXhwYW5kb107IGlmICh2b2lkIDAgIT09IHIpIHsgaWYgKHZvaWQgMCAhPT0gdCkgeyBuID0gKHQgPSBBcnJheS5pc0FycmF5KHQpID8gdC5tYXAoUSkgOiAodCA9IFEodCkpIGluIHIgPyBbdF0gOiB0Lm1hdGNoKEkpIHx8IFtdKS5sZW5ndGg7IHdoaWxlIChuLS0pIGRlbGV0ZSByW3Rbbl1dIH0gKHZvaWQgMCA9PT0gdCB8fCB3LmlzRW1wdHlPYmplY3QocikpICYmIChlLm5vZGVUeXBlID8gZVt0aGlzLmV4cGFuZG9dID0gdm9pZCAwIDogZGVsZXRlIGVbdGhpcy5leHBhbmRvXSkgfSB9LCBoYXNEYXRhOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGVbdGhpcy5leHBhbmRvXTsgcmV0dXJuIHZvaWQgMCAhPT0gdCAmJiAhdy5pc0VtcHR5T2JqZWN0KHQpIH0gfTsgdmFyIEsgPSBuZXcgRywgSiA9IG5ldyBHLCBaID0gL14oPzpce1tcd1xXXSpcfXxcW1tcd1xXXSpcXSkkLywgZWUgPSAvW0EtWl0vZzsgZnVuY3Rpb24gdGUoZSkgeyByZXR1cm4gInRydWUiID09PSBlIHx8ICJmYWxzZSIgIT09IGUgJiYgKCJudWxsIiA9PT0gZSA/IG51bGwgOiBlID09PSArZSArICIiID8gK2UgOiBaLnRlc3QoZSkgPyBKU09OLnBhcnNlKGUpIDogZSkgfSBmdW5jdGlvbiBuZShlLCB0LCBuKSB7IHZhciByOyBpZiAodm9pZCAwID09PSBuICYmIDEgPT09IGUubm9kZVR5cGUpIGlmIChyID0gImRhdGEtIiArIHQucmVwbGFjZShlZSwgIi0kJiIpLnRvTG93ZXJDYXNlKCksICJzdHJpbmciID09IHR5cGVvZiAobiA9IGUuZ2V0QXR0cmlidXRlKHIpKSkgeyB0cnkgeyBuID0gdGUobikgfSBjYXRjaCAoZSkgeyB9IEouc2V0KGUsIHQsIG4pIH0gZWxzZSBuID0gdm9pZCAwOyByZXR1cm4gbiB9IHcuZXh0ZW5kKHsgaGFzRGF0YTogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEouaGFzRGF0YShlKSB8fCBLLmhhc0RhdGEoZSkgfSwgZGF0YTogZnVuY3Rpb24gKGUsIHQsIG4pIHsgcmV0dXJuIEouYWNjZXNzKGUsIHQsIG4pIH0sIHJlbW92ZURhdGE6IGZ1bmN0aW9uIChlLCB0KSB7IEoucmVtb3ZlKGUsIHQpIH0sIF9kYXRhOiBmdW5jdGlvbiAoZSwgdCwgbikgeyByZXR1cm4gSy5hY2Nlc3MoZSwgdCwgbikgfSwgX3JlbW92ZURhdGE6IGZ1bmN0aW9uIChlLCB0KSB7IEsucmVtb3ZlKGUsIHQpIH0gfSksIHcuZm4uZXh0ZW5kKHsgZGF0YTogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIsIGksIG8gPSB0aGlzWzBdLCBhID0gbyAmJiBvLmF0dHJpYnV0ZXM7IGlmICh2b2lkIDAgPT09IGUpIHsgaWYgKHRoaXMubGVuZ3RoICYmIChpID0gSi5nZXQobyksIDEgPT09IG8ubm9kZVR5cGUgJiYgIUsuZ2V0KG8sICJoYXNEYXRhQXR0cnMiKSkpIHsgbiA9IGEubGVuZ3RoOyB3aGlsZSAobi0tKSBhW25dICYmIDAgPT09IChyID0gYVtuXS5uYW1lKS5pbmRleE9mKCJkYXRhLSIpICYmIChyID0gUShyLnNsaWNlKDUpKSwgbmUobywgciwgaVtyXSkpOyBLLnNldChvLCAiaGFzRGF0YUF0dHJzIiwgITApIH0gcmV0dXJuIGkgfSByZXR1cm4gIm9iamVjdCIgPT0gdHlwZW9mIGUgPyB0aGlzLmVhY2goZnVuY3Rpb24gKCkgeyBKLnNldCh0aGlzLCBlKSB9KSA6IF8odGhpcywgZnVuY3Rpb24gKHQpIHsgdmFyIG47IGlmIChvICYmIHZvaWQgMCA9PT0gdCkgeyBpZiAodm9pZCAwICE9PSAobiA9IEouZ2V0KG8sIGUpKSkgcmV0dXJuIG47IGlmICh2b2lkIDAgIT09IChuID0gbmUobywgZSkpKSByZXR1cm4gbiB9IGVsc2UgdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgSi5zZXQodGhpcywgZSwgdCkgfSkgfSwgbnVsbCwgdCwgYXJndW1lbnRzLmxlbmd0aCA+IDEsIG51bGwsICEwKSB9LCByZW1vdmVEYXRhOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgSi5yZW1vdmUodGhpcywgZSkgfSkgfSB9KSwgdy5leHRlbmQoeyBxdWV1ZTogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHI7IGlmIChlKSByZXR1cm4gdCA9ICh0IHx8ICJmeCIpICsgInF1ZXVlIiwgciA9IEsuZ2V0KGUsIHQpLCBuICYmICghciB8fCBBcnJheS5pc0FycmF5KG4pID8gciA9IEsuYWNjZXNzKGUsIHQsIHcubWFrZUFycmF5KG4pKSA6IHIucHVzaChuKSksIHIgfHwgW10gfSwgZGVxdWV1ZTogZnVuY3Rpb24gKGUsIHQpIHsgdCA9IHQgfHwgImZ4IjsgdmFyIG4gPSB3LnF1ZXVlKGUsIHQpLCByID0gbi5sZW5ndGgsIGkgPSBuLnNoaWZ0KCksIG8gPSB3Ll9xdWV1ZUhvb2tzKGUsIHQpLCBhID0gZnVuY3Rpb24gKCkgeyB3LmRlcXVldWUoZSwgdCkgfTsgImlucHJvZ3Jlc3MiID09PSBpICYmIChpID0gbi5zaGlmdCgpLCByLS0pLCBpICYmICgiZngiID09PSB0ICYmIG4udW5zaGlmdCgiaW5wcm9ncmVzcyIpLCBkZWxldGUgby5zdG9wLCBpLmNhbGwoZSwgYSwgbykpLCAhciAmJiBvICYmIG8uZW1wdHkuZmlyZSgpIH0sIF9xdWV1ZUhvb2tzOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IHQgKyAicXVldWVIb29rcyI7IHJldHVybiBLLmdldChlLCBuKSB8fCBLLmFjY2VzcyhlLCBuLCB7IGVtcHR5OiB3LkNhbGxiYWNrcygib25jZSBtZW1vcnkiKS5hZGQoZnVuY3Rpb24gKCkgeyBLLnJlbW92ZShlLCBbdCArICJxdWV1ZSIsIG5dKSB9KSB9KSB9IH0pLCB3LmZuLmV4dGVuZCh7IHF1ZXVlOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IDI7IHJldHVybiAic3RyaW5nIiAhPSB0eXBlb2YgZSAmJiAodCA9IGUsIGUgPSAiZngiLCBuLS0pLCBhcmd1bWVudHMubGVuZ3RoIDwgbiA/IHcucXVldWUodGhpc1swXSwgZSkgOiB2b2lkIDAgPT09IHQgPyB0aGlzIDogdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgdmFyIG4gPSB3LnF1ZXVlKHRoaXMsIGUsIHQpOyB3Ll9xdWV1ZUhvb2tzKHRoaXMsIGUpLCAiZngiID09PSBlICYmICJpbnByb2dyZXNzIiAhPT0gblswXSAmJiB3LmRlcXVldWUodGhpcywgZSkgfSkgfSwgZGVxdWV1ZTogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7IHcuZGVxdWV1ZSh0aGlzLCBlKSB9KSB9LCBjbGVhclF1ZXVlOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5xdWV1ZShlIHx8ICJmeCIsIFtdKSB9LCBwcm9taXNlOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiwgciA9IDEsIGkgPSB3LkRlZmVycmVkKCksIG8gPSB0aGlzLCBhID0gdGhpcy5sZW5ndGgsIHUgPSBmdW5jdGlvbiAoKSB7IC0tciB8fCBpLnJlc29sdmVXaXRoKG8sIFtvXSkgfTsgInN0cmluZyIgIT0gdHlwZW9mIGUgJiYgKHQgPSBlLCBlID0gdm9pZCAwKSwgZSA9IGUgfHwgImZ4Ijsgd2hpbGUgKGEtLSkgKG4gPSBLLmdldChvW2FdLCBlICsgInF1ZXVlSG9va3MiKSkgJiYgbi5lbXB0eSAmJiAocisrICwgbi5lbXB0eS5hZGQodSkpOyByZXR1cm4gdSgpLCBpLnByb21pc2UodCkgfSB9KTsgdmFyIHJlID0gL1srLV0/KD86XGQqXC58KVxkKyg/OltlRV1bKy1dP1xkK3wpLy5zb3VyY2UsIGllID0gbmV3IFJlZ0V4cCgiXig/OihbKy1dKT18KSgiICsgcmUgKyAiKShbYS16JV0qKSQiLCAiaSIpLCBvZSA9IFsiVG9wIiwgIlJpZ2h0IiwgIkJvdHRvbSIsICJMZWZ0Il0sIGFlID0gZnVuY3Rpb24gKGUsIHQpIHsgcmV0dXJuICJub25lIiA9PT0gKGUgPSB0IHx8IGUpLnN0eWxlLmRpc3BsYXkgfHwgIiIgPT09IGUuc3R5bGUuZGlzcGxheSAmJiB3LmNvbnRhaW5zKGUub3duZXJEb2N1bWVudCwgZSkgJiYgIm5vbmUiID09PSB3LmNzcyhlLCAiZGlzcGxheSIpIH0sIHVlID0gZnVuY3Rpb24gKGUsIHQsIG4sIHIpIHsgdmFyIGksIG8sIGEgPSB7fTsgZm9yIChvIGluIHQpIGFbb10gPSBlLnN0eWxlW29dLCBlLnN0eWxlW29dID0gdFtvXTsgaSA9IG4uYXBwbHkoZSwgciB8fCBbXSk7IGZvciAobyBpbiB0KSBlLnN0eWxlW29dID0gYVtvXTsgcmV0dXJuIGkgfTsgZnVuY3Rpb24gc2UoZSwgdCwgbiwgcikgeyB2YXIgaSwgbywgYSA9IDIwLCB1ID0gciA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHIuY3VyKCkgfSA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHcuY3NzKGUsIHQsICIiKSB9LCBzID0gdSgpLCBsID0gbiAmJiBuWzNdIHx8ICh3LmNzc051bWJlclt0XSA/ICIiIDogInB4IiksIGMgPSAody5jc3NOdW1iZXJbdF0gfHwgInB4IiAhPT0gbCAmJiArcykgJiYgaWUuZXhlYyh3LmNzcyhlLCB0KSk7IGlmIChjICYmIGNbM10gIT09IGwpIHsgcyAvPSAyLCBsID0gbCB8fCBjWzNdLCBjID0gK3MgfHwgMTsgd2hpbGUgKGEtLSkgdy5zdHlsZShlLCB0LCBjICsgbCksICgxIC0gbykgKiAoMSAtIChvID0gdSgpIC8gcyB8fCAuNSkpIDw9IDAgJiYgKGEgPSAwKSwgYyAvPSBvOyBjICo9IDIsIHcuc3R5bGUoZSwgdCwgYyArIGwpLCBuID0gbiB8fCBbXSB9IHJldHVybiBuICYmIChjID0gK2MgfHwgK3MgfHwgMCwgaSA9IG5bMV0gPyBjICsgKG5bMV0gKyAxKSAqIG5bMl0gOiArblsyXSwgciAmJiAoci51bml0ID0gbCwgci5zdGFydCA9IGMsIHIuZW5kID0gaSkpLCBpIH0gdmFyIGxlID0ge307IGZ1bmN0aW9uIGNlKGUpIHsgdmFyIHQsIG4gPSBlLm93bmVyRG9jdW1lbnQsIHIgPSBlLm5vZGVOYW1lLCBpID0gbGVbcl07IHJldHVybiBpIHx8ICh0ID0gbi5ib2R5LmFwcGVuZENoaWxkKG4uY3JlYXRlRWxlbWVudChyKSksIGkgPSB3LmNzcyh0LCAiZGlzcGxheSIpLCB0LnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodCksICJub25lIiA9PT0gaSAmJiAoaSA9ICJibG9jayIpLCBsZVtyXSA9IGksIGkpIH0gZnVuY3Rpb24gZmUoZSwgdCkgeyBmb3IgKHZhciBuLCByLCBpID0gW10sIG8gPSAwLCBhID0gZS5sZW5ndGg7IG8gPCBhOyBvKyspKHIgPSBlW29dKS5zdHlsZSAmJiAobiA9IHIuc3R5bGUuZGlzcGxheSwgdCA/ICgibm9uZSIgPT09IG4gJiYgKGlbb10gPSBLLmdldChyLCAiZGlzcGxheSIpIHx8IG51bGwsIGlbb10gfHwgKHIuc3R5bGUuZGlzcGxheSA9ICIiKSksICIiID09PSByLnN0eWxlLmRpc3BsYXkgJiYgYWUocikgJiYgKGlbb10gPSBjZShyKSkpIDogIm5vbmUiICE9PSBuICYmIChpW29dID0gIm5vbmUiLCBLLnNldChyLCAiZGlzcGxheSIsIG4pKSk7IGZvciAobyA9IDA7IG8gPCBhOyBvKyspbnVsbCAhPSBpW29dICYmIChlW29dLnN0eWxlLmRpc3BsYXkgPSBpW29dKTsgcmV0dXJuIGUgfSB3LmZuLmV4dGVuZCh7IHNob3c6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGZlKHRoaXMsICEwKSB9LCBoaWRlOiBmdW5jdGlvbiAoKSB7IHJldHVybiBmZSh0aGlzKSB9LCB0b2dnbGU6IGZ1bmN0aW9uIChlKSB7IHJldHVybiAiYm9vbGVhbiIgPT0gdHlwZW9mIGUgPyBlID8gdGhpcy5zaG93KCkgOiB0aGlzLmhpZGUoKSA6IHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7IGFlKHRoaXMpID8gdyh0aGlzKS5zaG93KCkgOiB3KHRoaXMpLmhpZGUoKSB9KSB9IH0pOyB2YXIgZGUgPSAvXig/OmNoZWNrYm94fHJhZGlvKSQvaSwgcGUgPSAvPChbYS16XVteXC9cMD5ceDIwXHRcclxuXGZdKykvaSwgaGUgPSAvXiR8Xm1vZHVsZSR8XC8oPzpqYXZhfGVjbWEpc2NyaXB0L2ksIGdlID0geyBvcHRpb246IFsxLCAiPHNlbGVjdCBtdWx0aXBsZT0nbXVsdGlwbGUnPiIsICI8L3NlbGVjdD4iXSwgdGhlYWQ6IFsxLCAiPHRhYmxlPiIsICI8L3RhYmxlPiJdLCBjb2w6IFsyLCAiPHRhYmxlPjxjb2xncm91cD4iLCAiPC9jb2xncm91cD48L3RhYmxlPiJdLCB0cjogWzIsICI8dGFibGU+PHRib2R5PiIsICI8L3Rib2R5PjwvdGFibGU+Il0sIHRkOiBbMywgIjx0YWJsZT48dGJvZHk+PHRyPiIsICI8L3RyPjwvdGJvZHk+PC90YWJsZT4iXSwgX2RlZmF1bHQ6IFswLCAiIiwgIiJdIH07IGdlLm9wdGdyb3VwID0gZ2Uub3B0aW9uLCBnZS50Ym9keSA9IGdlLnRmb290ID0gZ2UuY29sZ3JvdXAgPSBnZS5jYXB0aW9uID0gZ2UudGhlYWQsIGdlLnRoID0gZ2UudGQ7IGZ1bmN0aW9uIHZlKGUsIHQpIHsgdmFyIG47IHJldHVybiBuID0gInVuZGVmaW5lZCIgIT0gdHlwZW9mIGUuZ2V0RWxlbWVudHNCeVRhZ05hbWUgPyBlLmdldEVsZW1lbnRzQnlUYWdOYW1lKHQgfHwgIioiKSA6ICJ1bmRlZmluZWQiICE9IHR5cGVvZiBlLnF1ZXJ5U2VsZWN0b3JBbGwgPyBlLnF1ZXJ5U2VsZWN0b3JBbGwodCB8fCAiKiIpIDogW10sIHZvaWQgMCA9PT0gdCB8fCB0ICYmIEQoZSwgdCkgPyB3Lm1lcmdlKFtlXSwgbikgOiBuIH0gZnVuY3Rpb24geWUoZSwgdCkgeyBmb3IgKHZhciBuID0gMCwgciA9IGUubGVuZ3RoOyBuIDwgcjsgbisrKUsuc2V0KGVbbl0sICJnbG9iYWxFdmFsIiwgIXQgfHwgSy5nZXQodFtuXSwgImdsb2JhbEV2YWwiKSkgfSB2YXIgbWUgPSAvPHwmIz9cdys7LzsgZnVuY3Rpb24gYmUoZSwgdCwgbiwgciwgaSkgeyBmb3IgKHZhciBvLCBhLCB1LCBzLCBsLCBjLCBmID0gdC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCksIGQgPSBbXSwgcCA9IDAsIGggPSBlLmxlbmd0aDsgcCA8IGg7IHArKylpZiAoKG8gPSBlW3BdKSB8fCAwID09PSBvKSBpZiAoIm9iamVjdCIgPT09IGIobykpIHcubWVyZ2UoZCwgby5ub2RlVHlwZSA/IFtvXSA6IG8pOyBlbHNlIGlmIChtZS50ZXN0KG8pKSB7IGEgPSBhIHx8IGYuYXBwZW5kQ2hpbGQodC5jcmVhdGVFbGVtZW50KCJkaXYiKSksIHUgPSAocGUuZXhlYyhvKSB8fCBbIiIsICIiXSlbMV0udG9Mb3dlckNhc2UoKSwgcyA9IGdlW3VdIHx8IGdlLl9kZWZhdWx0LCBhLmlubmVySFRNTCA9IHNbMV0gKyB3Lmh0bWxQcmVmaWx0ZXIobykgKyBzWzJdLCBjID0gc1swXTsgd2hpbGUgKGMtLSkgYSA9IGEubGFzdENoaWxkOyB3Lm1lcmdlKGQsIGEuY2hpbGROb2RlcyksIChhID0gZi5maXJzdENoaWxkKS50ZXh0Q29udGVudCA9ICIiIH0gZWxzZSBkLnB1c2godC5jcmVhdGVUZXh0Tm9kZShvKSk7IGYudGV4dENvbnRlbnQgPSAiIiwgcCA9IDA7IHdoaWxlIChvID0gZFtwKytdKSBpZiAociAmJiB3LmluQXJyYXkobywgcikgPiAtMSkgaSAmJiBpLnB1c2gobyk7IGVsc2UgaWYgKGwgPSB3LmNvbnRhaW5zKG8ub3duZXJEb2N1bWVudCwgbyksIGEgPSB2ZShmLmFwcGVuZENoaWxkKG8pLCAic2NyaXB0IiksIGwgJiYgeWUoYSksIG4pIHsgYyA9IDA7IHdoaWxlIChvID0gYVtjKytdKSBoZS50ZXN0KG8udHlwZSB8fCAiIikgJiYgbi5wdXNoKG8pIH0gcmV0dXJuIGYgfSAhZnVuY3Rpb24gKCkgeyB2YXIgZSA9IHIuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLmFwcGVuZENoaWxkKHIuY3JlYXRlRWxlbWVudCgiZGl2IikpLCB0ID0gci5jcmVhdGVFbGVtZW50KCJpbnB1dCIpOyB0LnNldEF0dHJpYnV0ZSgidHlwZSIsICJyYWRpbyIpLCB0LnNldEF0dHJpYnV0ZSgiY2hlY2tlZCIsICJjaGVja2VkIiksIHQuc2V0QXR0cmlidXRlKCJuYW1lIiwgInQiKSwgZS5hcHBlbmRDaGlsZCh0KSwgaC5jaGVja0Nsb25lID0gZS5jbG9uZU5vZGUoITApLmNsb25lTm9kZSghMCkubGFzdENoaWxkLmNoZWNrZWQsIGUuaW5uZXJIVE1MID0gIjx0ZXh0YXJlYT54PC90ZXh0YXJlYT4iLCBoLm5vQ2xvbmVDaGVja2VkID0gISFlLmNsb25lTm9kZSghMCkubGFzdENoaWxkLmRlZmF1bHRWYWx1ZSB9KCk7IHZhciB4ZSA9IHIuZG9jdW1lbnRFbGVtZW50LCB3ZSA9IC9ea2V5LywgQ2UgPSAvXig/Om1vdXNlfHBvaW50ZXJ8Y29udGV4dG1lbnV8ZHJhZ3xkcm9wKXxjbGljay8sIFRlID0gL14oW14uXSopKD86XC4oLispfCkvOyBmdW5jdGlvbiBFZSgpIHsgcmV0dXJuICEwIH0gZnVuY3Rpb24gTmUoKSB7IHJldHVybiAhMSB9IGZ1bmN0aW9uIGtlKCkgeyB0cnkgeyByZXR1cm4gci5hY3RpdmVFbGVtZW50IH0gY2F0Y2ggKGUpIHsgfSB9IGZ1bmN0aW9uIEFlKGUsIHQsIG4sIHIsIGksIG8pIHsgdmFyIGEsIHU7IGlmICgib2JqZWN0IiA9PSB0eXBlb2YgdCkgeyAic3RyaW5nIiAhPSB0eXBlb2YgbiAmJiAociA9IHIgfHwgbiwgbiA9IHZvaWQgMCk7IGZvciAodSBpbiB0KSBBZShlLCB1LCBuLCByLCB0W3VdLCBvKTsgcmV0dXJuIGUgfSBpZiAobnVsbCA9PSByICYmIG51bGwgPT0gaSA/IChpID0gbiwgciA9IG4gPSB2b2lkIDApIDogbnVsbCA9PSBpICYmICgic3RyaW5nIiA9PSB0eXBlb2YgbiA/IChpID0gciwgciA9IHZvaWQgMCkgOiAoaSA9IHIsIHIgPSBuLCBuID0gdm9pZCAwKSksICExID09PSBpKSBpID0gTmU7IGVsc2UgaWYgKCFpKSByZXR1cm4gZTsgcmV0dXJuIDEgPT09IG8gJiYgKGEgPSBpLCAoaSA9IGZ1bmN0aW9uIChlKSB7IHJldHVybiB3KCkub2ZmKGUpLCBhLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykgfSkuZ3VpZCA9IGEuZ3VpZCB8fCAoYS5ndWlkID0gdy5ndWlkKyspKSwgZS5lYWNoKGZ1bmN0aW9uICgpIHsgdy5ldmVudC5hZGQodGhpcywgdCwgaSwgciwgbikgfSkgfSB3LmV2ZW50ID0geyBnbG9iYWw6IHt9LCBhZGQ6IGZ1bmN0aW9uIChlLCB0LCBuLCByLCBpKSB7IHZhciBvLCBhLCB1LCBzLCBsLCBjLCBmLCBkLCBwLCBoLCBnLCB2ID0gSy5nZXQoZSk7IGlmICh2KSB7IG4uaGFuZGxlciAmJiAobiA9IChvID0gbikuaGFuZGxlciwgaSA9IG8uc2VsZWN0b3IpLCBpICYmIHcuZmluZC5tYXRjaGVzU2VsZWN0b3IoeGUsIGkpLCBuLmd1aWQgfHwgKG4uZ3VpZCA9IHcuZ3VpZCsrKSwgKHMgPSB2LmV2ZW50cykgfHwgKHMgPSB2LmV2ZW50cyA9IHt9KSwgKGEgPSB2LmhhbmRsZSkgfHwgKGEgPSB2LmhhbmRsZSA9IGZ1bmN0aW9uICh0KSB7IHJldHVybiAidW5kZWZpbmVkIiAhPSB0eXBlb2YgdyAmJiB3LmV2ZW50LnRyaWdnZXJlZCAhPT0gdC50eXBlID8gdy5ldmVudC5kaXNwYXRjaC5hcHBseShlLCBhcmd1bWVudHMpIDogdm9pZCAwIH0pLCBsID0gKHQgPSAodCB8fCAiIikubWF0Y2goSSkgfHwgWyIiXSkubGVuZ3RoOyB3aGlsZSAobC0tKSBwID0gZyA9ICh1ID0gVGUuZXhlYyh0W2xdKSB8fCBbXSlbMV0sIGggPSAodVsyXSB8fCAiIikuc3BsaXQoIi4iKS5zb3J0KCksIHAgJiYgKGYgPSB3LmV2ZW50LnNwZWNpYWxbcF0gfHwge30sIHAgPSAoaSA/IGYuZGVsZWdhdGVUeXBlIDogZi5iaW5kVHlwZSkgfHwgcCwgZiA9IHcuZXZlbnQuc3BlY2lhbFtwXSB8fCB7fSwgYyA9IHcuZXh0ZW5kKHsgdHlwZTogcCwgb3JpZ1R5cGU6IGcsIGRhdGE6IHIsIGhhbmRsZXI6IG4sIGd1aWQ6IG4uZ3VpZCwgc2VsZWN0b3I6IGksIG5lZWRzQ29udGV4dDogaSAmJiB3LmV4cHIubWF0Y2gubmVlZHNDb250ZXh0LnRlc3QoaSksIG5hbWVzcGFjZTogaC5qb2luKCIuIikgfSwgbyksIChkID0gc1twXSkgfHwgKChkID0gc1twXSA9IFtdKS5kZWxlZ2F0ZUNvdW50ID0gMCwgZi5zZXR1cCAmJiAhMSAhPT0gZi5zZXR1cC5jYWxsKGUsIHIsIGgsIGEpIHx8IGUuYWRkRXZlbnRMaXN0ZW5lciAmJiBlLmFkZEV2ZW50TGlzdGVuZXIocCwgYSkpLCBmLmFkZCAmJiAoZi5hZGQuY2FsbChlLCBjKSwgYy5oYW5kbGVyLmd1aWQgfHwgKGMuaGFuZGxlci5ndWlkID0gbi5ndWlkKSksIGkgPyBkLnNwbGljZShkLmRlbGVnYXRlQ291bnQrKywgMCwgYykgOiBkLnB1c2goYyksIHcuZXZlbnQuZ2xvYmFsW3BdID0gITApIH0gfSwgcmVtb3ZlOiBmdW5jdGlvbiAoZSwgdCwgbiwgciwgaSkgeyB2YXIgbywgYSwgdSwgcywgbCwgYywgZiwgZCwgcCwgaCwgZywgdiA9IEsuaGFzRGF0YShlKSAmJiBLLmdldChlKTsgaWYgKHYgJiYgKHMgPSB2LmV2ZW50cykpIHsgbCA9ICh0ID0gKHQgfHwgIiIpLm1hdGNoKEkpIHx8IFsiIl0pLmxlbmd0aDsgd2hpbGUgKGwtLSkgaWYgKHUgPSBUZS5leGVjKHRbbF0pIHx8IFtdLCBwID0gZyA9IHVbMV0sIGggPSAodVsyXSB8fCAiIikuc3BsaXQoIi4iKS5zb3J0KCksIHApIHsgZiA9IHcuZXZlbnQuc3BlY2lhbFtwXSB8fCB7fSwgZCA9IHNbcCA9IChyID8gZi5kZWxlZ2F0ZVR5cGUgOiBmLmJpbmRUeXBlKSB8fCBwXSB8fCBbXSwgdSA9IHVbMl0gJiYgbmV3IFJlZ0V4cCgiKF58XFwuKSIgKyBoLmpvaW4oIlxcLig/Oi4qXFwufCkiKSArICIoXFwufCQpIiksIGEgPSBvID0gZC5sZW5ndGg7IHdoaWxlIChvLS0pIGMgPSBkW29dLCAhaSAmJiBnICE9PSBjLm9yaWdUeXBlIHx8IG4gJiYgbi5ndWlkICE9PSBjLmd1aWQgfHwgdSAmJiAhdS50ZXN0KGMubmFtZXNwYWNlKSB8fCByICYmIHIgIT09IGMuc2VsZWN0b3IgJiYgKCIqKiIgIT09IHIgfHwgIWMuc2VsZWN0b3IpIHx8IChkLnNwbGljZShvLCAxKSwgYy5zZWxlY3RvciAmJiBkLmRlbGVnYXRlQ291bnQtLSAsIGYucmVtb3ZlICYmIGYucmVtb3ZlLmNhbGwoZSwgYykpOyBhICYmICFkLmxlbmd0aCAmJiAoZi50ZWFyZG93biAmJiAhMSAhPT0gZi50ZWFyZG93bi5jYWxsKGUsIGgsIHYuaGFuZGxlKSB8fCB3LnJlbW92ZUV2ZW50KGUsIHAsIHYuaGFuZGxlKSwgZGVsZXRlIHNbcF0pIH0gZWxzZSBmb3IgKHAgaW4gcykgdy5ldmVudC5yZW1vdmUoZSwgcCArIHRbbF0sIG4sIHIsICEwKTsgdy5pc0VtcHR5T2JqZWN0KHMpICYmIEsucmVtb3ZlKGUsICJoYW5kbGUgZXZlbnRzIikgfSB9LCBkaXNwYXRjaDogZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSB3LmV2ZW50LmZpeChlKSwgbiwgciwgaSwgbywgYSwgdSwgcyA9IG5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoKSwgbCA9IChLLmdldCh0aGlzLCAiZXZlbnRzIikgfHwge30pW3QudHlwZV0gfHwgW10sIGMgPSB3LmV2ZW50LnNwZWNpYWxbdC50eXBlXSB8fCB7fTsgZm9yIChzWzBdID0gdCwgbiA9IDE7IG4gPCBhcmd1bWVudHMubGVuZ3RoOyBuKyspc1tuXSA9IGFyZ3VtZW50c1tuXTsgaWYgKHQuZGVsZWdhdGVUYXJnZXQgPSB0aGlzLCAhYy5wcmVEaXNwYXRjaCB8fCAhMSAhPT0gYy5wcmVEaXNwYXRjaC5jYWxsKHRoaXMsIHQpKSB7IHUgPSB3LmV2ZW50LmhhbmRsZXJzLmNhbGwodGhpcywgdCwgbCksIG4gPSAwOyB3aGlsZSAoKG8gPSB1W24rK10pICYmICF0LmlzUHJvcGFnYXRpb25TdG9wcGVkKCkpIHsgdC5jdXJyZW50VGFyZ2V0ID0gby5lbGVtLCByID0gMDsgd2hpbGUgKChhID0gby5oYW5kbGVyc1tyKytdKSAmJiAhdC5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCgpKSB0LnJuYW1lc3BhY2UgJiYgIXQucm5hbWVzcGFjZS50ZXN0KGEubmFtZXNwYWNlKSB8fCAodC5oYW5kbGVPYmogPSBhLCB0LmRhdGEgPSBhLmRhdGEsIHZvaWQgMCAhPT0gKGkgPSAoKHcuZXZlbnQuc3BlY2lhbFthLm9yaWdUeXBlXSB8fCB7fSkuaGFuZGxlIHx8IGEuaGFuZGxlcikuYXBwbHkoby5lbGVtLCBzKSkgJiYgITEgPT09ICh0LnJlc3VsdCA9IGkpICYmICh0LnByZXZlbnREZWZhdWx0KCksIHQuc3RvcFByb3BhZ2F0aW9uKCkpKSB9IHJldHVybiBjLnBvc3REaXNwYXRjaCAmJiBjLnBvc3REaXNwYXRjaC5jYWxsKHRoaXMsIHQpLCB0LnJlc3VsdCB9IH0sIGhhbmRsZXJzOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiwgciwgaSwgbywgYSwgdSA9IFtdLCBzID0gdC5kZWxlZ2F0ZUNvdW50LCBsID0gZS50YXJnZXQ7IGlmIChzICYmIGwubm9kZVR5cGUgJiYgISgiY2xpY2siID09PSBlLnR5cGUgJiYgZS5idXR0b24gPj0gMSkpIGZvciAoOyBsICE9PSB0aGlzOyBsID0gbC5wYXJlbnROb2RlIHx8IHRoaXMpaWYgKDEgPT09IGwubm9kZVR5cGUgJiYgKCJjbGljayIgIT09IGUudHlwZSB8fCAhMCAhPT0gbC5kaXNhYmxlZCkpIHsgZm9yIChvID0gW10sIGEgPSB7fSwgbiA9IDA7IG4gPCBzOyBuKyspdm9pZCAwID09PSBhW2kgPSAociA9IHRbbl0pLnNlbGVjdG9yICsgIiAiXSAmJiAoYVtpXSA9IHIubmVlZHNDb250ZXh0ID8gdyhpLCB0aGlzKS5pbmRleChsKSA+IC0xIDogdy5maW5kKGksIHRoaXMsIG51bGwsIFtsXSkubGVuZ3RoKSwgYVtpXSAmJiBvLnB1c2gocik7IG8ubGVuZ3RoICYmIHUucHVzaCh7IGVsZW06IGwsIGhhbmRsZXJzOiBvIH0pIH0gcmV0dXJuIGwgPSB0aGlzLCBzIDwgdC5sZW5ndGggJiYgdS5wdXNoKHsgZWxlbTogbCwgaGFuZGxlcnM6IHQuc2xpY2UocykgfSksIHUgfSwgYWRkUHJvcDogZnVuY3Rpb24gKGUsIHQpIHsgT2JqZWN0LmRlZmluZVByb3BlcnR5KHcuRXZlbnQucHJvdG90eXBlLCBlLCB7IGVudW1lcmFibGU6ICEwLCBjb25maWd1cmFibGU6ICEwLCBnZXQ6IGcodCkgPyBmdW5jdGlvbiAoKSB7IGlmICh0aGlzLm9yaWdpbmFsRXZlbnQpIHJldHVybiB0KHRoaXMub3JpZ2luYWxFdmVudCkgfSA6IGZ1bmN0aW9uICgpIHsgaWYgKHRoaXMub3JpZ2luYWxFdmVudCkgcmV0dXJuIHRoaXMub3JpZ2luYWxFdmVudFtlXSB9LCBzZXQ6IGZ1bmN0aW9uICh0KSB7IE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBlLCB7IGVudW1lcmFibGU6ICEwLCBjb25maWd1cmFibGU6ICEwLCB3cml0YWJsZTogITAsIHZhbHVlOiB0IH0pIH0gfSkgfSwgZml4OiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZVt3LmV4cGFuZG9dID8gZSA6IG5ldyB3LkV2ZW50KGUpIH0sIHNwZWNpYWw6IHsgbG9hZDogeyBub0J1YmJsZTogITAgfSwgZm9jdXM6IHsgdHJpZ2dlcjogZnVuY3Rpb24gKCkgeyBpZiAodGhpcyAhPT0ga2UoKSAmJiB0aGlzLmZvY3VzKSByZXR1cm4gdGhpcy5mb2N1cygpLCAhMSB9LCBkZWxlZ2F0ZVR5cGU6ICJmb2N1c2luIiB9LCBibHVyOiB7IHRyaWdnZXI6IGZ1bmN0aW9uICgpIHsgaWYgKHRoaXMgPT09IGtlKCkgJiYgdGhpcy5ibHVyKSByZXR1cm4gdGhpcy5ibHVyKCksICExIH0sIGRlbGVnYXRlVHlwZTogImZvY3Vzb3V0IiB9LCBjbGljazogeyB0cmlnZ2VyOiBmdW5jdGlvbiAoKSB7IGlmICgiY2hlY2tib3giID09PSB0aGlzLnR5cGUgJiYgdGhpcy5jbGljayAmJiBEKHRoaXMsICJpbnB1dCIpKSByZXR1cm4gdGhpcy5jbGljaygpLCAhMSB9LCBfZGVmYXVsdDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEQoZS50YXJnZXQsICJhIikgfSB9LCBiZWZvcmV1bmxvYWQ6IHsgcG9zdERpc3BhdGNoOiBmdW5jdGlvbiAoZSkgeyB2b2lkIDAgIT09IGUucmVzdWx0ICYmIGUub3JpZ2luYWxFdmVudCAmJiAoZS5vcmlnaW5hbEV2ZW50LnJldHVyblZhbHVlID0gZS5yZXN1bHQpIH0gfSB9IH0sIHcucmVtb3ZlRXZlbnQgPSBmdW5jdGlvbiAoZSwgdCwgbikgeyBlLnJlbW92ZUV2ZW50TGlzdGVuZXIgJiYgZS5yZW1vdmVFdmVudExpc3RlbmVyKHQsIG4pIH0sIHcuRXZlbnQgPSBmdW5jdGlvbiAoZSwgdCkgeyBpZiAoISh0aGlzIGluc3RhbmNlb2Ygdy5FdmVudCkpIHJldHVybiBuZXcgdy5FdmVudChlLCB0KTsgZSAmJiBlLnR5cGUgPyAodGhpcy5vcmlnaW5hbEV2ZW50ID0gZSwgdGhpcy50eXBlID0gZS50eXBlLCB0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IGUuZGVmYXVsdFByZXZlbnRlZCB8fCB2b2lkIDAgPT09IGUuZGVmYXVsdFByZXZlbnRlZCAmJiAhMSA9PT0gZS5yZXR1cm5WYWx1ZSA/IEVlIDogTmUsIHRoaXMudGFyZ2V0ID0gZS50YXJnZXQgJiYgMyA9PT0gZS50YXJnZXQubm9kZVR5cGUgPyBlLnRhcmdldC5wYXJlbnROb2RlIDogZS50YXJnZXQsIHRoaXMuY3VycmVudFRhcmdldCA9IGUuY3VycmVudFRhcmdldCwgdGhpcy5yZWxhdGVkVGFyZ2V0ID0gZS5yZWxhdGVkVGFyZ2V0KSA6IHRoaXMudHlwZSA9IGUsIHQgJiYgdy5leHRlbmQodGhpcywgdCksIHRoaXMudGltZVN0YW1wID0gZSAmJiBlLnRpbWVTdGFtcCB8fCBEYXRlLm5vdygpLCB0aGlzW3cuZXhwYW5kb10gPSAhMCB9LCB3LkV2ZW50LnByb3RvdHlwZSA9IHsgY29uc3RydWN0b3I6IHcuRXZlbnQsIGlzRGVmYXVsdFByZXZlbnRlZDogTmUsIGlzUHJvcGFnYXRpb25TdG9wcGVkOiBOZSwgaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQ6IE5lLCBpc1NpbXVsYXRlZDogITEsIHByZXZlbnREZWZhdWx0OiBmdW5jdGlvbiAoKSB7IHZhciBlID0gdGhpcy5vcmlnaW5hbEV2ZW50OyB0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IEVlLCBlICYmICF0aGlzLmlzU2ltdWxhdGVkICYmIGUucHJldmVudERlZmF1bHQoKSB9LCBzdG9wUHJvcGFnYXRpb246IGZ1bmN0aW9uICgpIHsgdmFyIGUgPSB0aGlzLm9yaWdpbmFsRXZlbnQ7IHRoaXMuaXNQcm9wYWdhdGlvblN0b3BwZWQgPSBFZSwgZSAmJiAhdGhpcy5pc1NpbXVsYXRlZCAmJiBlLnN0b3BQcm9wYWdhdGlvbigpIH0sIHN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbjogZnVuY3Rpb24gKCkgeyB2YXIgZSA9IHRoaXMub3JpZ2luYWxFdmVudDsgdGhpcy5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCA9IEVlLCBlICYmICF0aGlzLmlzU2ltdWxhdGVkICYmIGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCksIHRoaXMuc3RvcFByb3BhZ2F0aW9uKCkgfSB9LCB3LmVhY2goeyBhbHRLZXk6ICEwLCBidWJibGVzOiAhMCwgY2FuY2VsYWJsZTogITAsIGNoYW5nZWRUb3VjaGVzOiAhMCwgY3RybEtleTogITAsIGRldGFpbDogITAsIGV2ZW50UGhhc2U6ICEwLCBtZXRhS2V5OiAhMCwgcGFnZVg6ICEwLCBwYWdlWTogITAsIHNoaWZ0S2V5OiAhMCwgdmlldzogITAsICJjaGFyIjogITAsIGNoYXJDb2RlOiAhMCwga2V5OiAhMCwga2V5Q29kZTogITAsIGJ1dHRvbjogITAsIGJ1dHRvbnM6ICEwLCBjbGllbnRYOiAhMCwgY2xpZW50WTogITAsIG9mZnNldFg6ICEwLCBvZmZzZXRZOiAhMCwgcG9pbnRlcklkOiAhMCwgcG9pbnRlclR5cGU6ICEwLCBzY3JlZW5YOiAhMCwgc2NyZWVuWTogITAsIHRhcmdldFRvdWNoZXM6ICEwLCB0b0VsZW1lbnQ6ICEwLCB0b3VjaGVzOiAhMCwgd2hpY2g6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZS5idXR0b247IHJldHVybiBudWxsID09IGUud2hpY2ggJiYgd2UudGVzdChlLnR5cGUpID8gbnVsbCAhPSBlLmNoYXJDb2RlID8gZS5jaGFyQ29kZSA6IGUua2V5Q29kZSA6ICFlLndoaWNoICYmIHZvaWQgMCAhPT0gdCAmJiBDZS50ZXN0KGUudHlwZSkgPyAxICYgdCA/IDEgOiAyICYgdCA/IDMgOiA0ICYgdCA/IDIgOiAwIDogZS53aGljaCB9IH0sIHcuZXZlbnQuYWRkUHJvcCksIHcuZWFjaCh7IG1vdXNlZW50ZXI6ICJtb3VzZW92ZXIiLCBtb3VzZWxlYXZlOiAibW91c2VvdXQiLCBwb2ludGVyZW50ZXI6ICJwb2ludGVyb3ZlciIsIHBvaW50ZXJsZWF2ZTogInBvaW50ZXJvdXQiIH0sIGZ1bmN0aW9uIChlLCB0KSB7IHcuZXZlbnQuc3BlY2lhbFtlXSA9IHsgZGVsZWdhdGVUeXBlOiB0LCBiaW5kVHlwZTogdCwgaGFuZGxlOiBmdW5jdGlvbiAoZSkgeyB2YXIgbiwgciA9IHRoaXMsIGkgPSBlLnJlbGF0ZWRUYXJnZXQsIG8gPSBlLmhhbmRsZU9iajsgcmV0dXJuIGkgJiYgKGkgPT09IHIgfHwgdy5jb250YWlucyhyLCBpKSkgfHwgKGUudHlwZSA9IG8ub3JpZ1R5cGUsIG4gPSBvLmhhbmRsZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKSwgZS50eXBlID0gdCksIG4gfSB9IH0pLCB3LmZuLmV4dGVuZCh7IG9uOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyByZXR1cm4gQWUodGhpcywgZSwgdCwgbiwgcikgfSwgb25lOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyByZXR1cm4gQWUodGhpcywgZSwgdCwgbiwgciwgMSkgfSwgb2ZmOiBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciwgaTsgaWYgKGUgJiYgZS5wcmV2ZW50RGVmYXVsdCAmJiBlLmhhbmRsZU9iaikgcmV0dXJuIHIgPSBlLmhhbmRsZU9iaiwgdyhlLmRlbGVnYXRlVGFyZ2V0KS5vZmYoci5uYW1lc3BhY2UgPyByLm9yaWdUeXBlICsgIi4iICsgci5uYW1lc3BhY2UgOiByLm9yaWdUeXBlLCByLnNlbGVjdG9yLCByLmhhbmRsZXIpLCB0aGlzOyBpZiAoIm9iamVjdCIgPT0gdHlwZW9mIGUpIHsgZm9yIChpIGluIGUpIHRoaXMub2ZmKGksIHQsIGVbaV0pOyByZXR1cm4gdGhpcyB9IHJldHVybiAhMSAhPT0gdCAmJiAiZnVuY3Rpb24iICE9IHR5cGVvZiB0IHx8IChuID0gdCwgdCA9IHZvaWQgMCksICExID09PSBuICYmIChuID0gTmUpLCB0aGlzLmVhY2goZnVuY3Rpb24gKCkgeyB3LmV2ZW50LnJlbW92ZSh0aGlzLCBlLCBuLCB0KSB9KSB9IH0pOyB2YXIgRGUgPSAvPCg/IWFyZWF8YnJ8Y29sfGVtYmVkfGhyfGltZ3xpbnB1dHxsaW5rfG1ldGF8cGFyYW0pKChbYS16XVteXC9cMD5ceDIwXHRcclxuXGZdKilbXj5dKilcLz4vZ2ksIFNlID0gLzxzY3JpcHR8PHN0eWxlfDxsaW5rL2ksIExlID0gL2NoZWNrZWRccyooPzpbXj1dfD1ccyouY2hlY2tlZC4pL2ksIGplID0gL15ccyo8ISg/OlxbQ0RBVEFcW3wtLSl8KD86XF1cXXwtLSk+XHMqJC9nOyBmdW5jdGlvbiBxZShlLCB0KSB7IHJldHVybiBEKGUsICJ0YWJsZSIpICYmIEQoMTEgIT09IHQubm9kZVR5cGUgPyB0IDogdC5maXJzdENoaWxkLCAidHIiKSA/IHcoZSkuY2hpbGRyZW4oInRib2R5IilbMF0gfHwgZSA6IGUgfSBmdW5jdGlvbiBPZShlKSB7IHJldHVybiBlLnR5cGUgPSAobnVsbCAhPT0gZS5nZXRBdHRyaWJ1dGUoInR5cGUiKSkgKyAiLyIgKyBlLnR5cGUsIGUgfSBmdW5jdGlvbiBQZShlKSB7IHJldHVybiAidHJ1ZS8iID09PSAoZS50eXBlIHx8ICIiKS5zbGljZSgwLCA1KSA/IGUudHlwZSA9IGUudHlwZS5zbGljZSg1KSA6IGUucmVtb3ZlQXR0cmlidXRlKCJ0eXBlIiksIGUgfSBmdW5jdGlvbiBIZShlLCB0KSB7IHZhciBuLCByLCBpLCBvLCBhLCB1LCBzLCBsOyBpZiAoMSA9PT0gdC5ub2RlVHlwZSkgeyBpZiAoSy5oYXNEYXRhKGUpICYmIChvID0gSy5hY2Nlc3MoZSksIGEgPSBLLnNldCh0LCBvKSwgbCA9IG8uZXZlbnRzKSkgeyBkZWxldGUgYS5oYW5kbGUsIGEuZXZlbnRzID0ge307IGZvciAoaSBpbiBsKSBmb3IgKG4gPSAwLCByID0gbFtpXS5sZW5ndGg7IG4gPCByOyBuKyspdy5ldmVudC5hZGQodCwgaSwgbFtpXVtuXSkgfSBKLmhhc0RhdGEoZSkgJiYgKHUgPSBKLmFjY2VzcyhlKSwgcyA9IHcuZXh0ZW5kKHt9LCB1KSwgSi5zZXQodCwgcykpIH0gfSBmdW5jdGlvbiBJZShlLCB0KSB7IHZhciBuID0gdC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpOyAiaW5wdXQiID09PSBuICYmIGRlLnRlc3QoZS50eXBlKSA/IHQuY2hlY2tlZCA9IGUuY2hlY2tlZCA6ICJpbnB1dCIgIT09IG4gJiYgInRleHRhcmVhIiAhPT0gbiB8fCAodC5kZWZhdWx0VmFsdWUgPSBlLmRlZmF1bHRWYWx1ZSkgfSBmdW5jdGlvbiBSZShlLCB0LCBuLCByKSB7IHQgPSBhLmFwcGx5KFtdLCB0KTsgdmFyIGksIG8sIHUsIHMsIGwsIGMsIGYgPSAwLCBkID0gZS5sZW5ndGgsIHAgPSBkIC0gMSwgdiA9IHRbMF0sIHkgPSBnKHYpOyBpZiAoeSB8fCBkID4gMSAmJiAic3RyaW5nIiA9PSB0eXBlb2YgdiAmJiAhaC5jaGVja0Nsb25lICYmIExlLnRlc3QodikpIHJldHVybiBlLmVhY2goZnVuY3Rpb24gKGkpIHsgdmFyIG8gPSBlLmVxKGkpOyB5ICYmICh0WzBdID0gdi5jYWxsKHRoaXMsIGksIG8uaHRtbCgpKSksIFJlKG8sIHQsIG4sIHIpIH0pOyBpZiAoZCAmJiAoaSA9IGJlKHQsIGVbMF0ub3duZXJEb2N1bWVudCwgITEsIGUsIHIpLCBvID0gaS5maXJzdENoaWxkLCAxID09PSBpLmNoaWxkTm9kZXMubGVuZ3RoICYmIChpID0gbyksIG8gfHwgcikpIHsgZm9yIChzID0gKHUgPSB3Lm1hcCh2ZShpLCAic2NyaXB0IiksIE9lKSkubGVuZ3RoOyBmIDwgZDsgZisrKWwgPSBpLCBmICE9PSBwICYmIChsID0gdy5jbG9uZShsLCAhMCwgITApLCBzICYmIHcubWVyZ2UodSwgdmUobCwgInNjcmlwdCIpKSksIG4uY2FsbChlW2ZdLCBsLCBmKTsgaWYgKHMpIGZvciAoYyA9IHVbdS5sZW5ndGggLSAxXS5vd25lckRvY3VtZW50LCB3Lm1hcCh1LCBQZSksIGYgPSAwOyBmIDwgczsgZisrKWwgPSB1W2ZdLCBoZS50ZXN0KGwudHlwZSB8fCAiIikgJiYgIUsuYWNjZXNzKGwsICJnbG9iYWxFdmFsIikgJiYgdy5jb250YWlucyhjLCBsKSAmJiAobC5zcmMgJiYgIm1vZHVsZSIgIT09IChsLnR5cGUgfHwgIiIpLnRvTG93ZXJDYXNlKCkgPyB3Ll9ldmFsVXJsICYmIHcuX2V2YWxVcmwobC5zcmMpIDogbShsLnRleHRDb250ZW50LnJlcGxhY2UoamUsICIiKSwgYywgbCkpIH0gcmV0dXJuIGUgfSBmdW5jdGlvbiBCZShlLCB0LCBuKSB7IGZvciAodmFyIHIsIGkgPSB0ID8gdy5maWx0ZXIodCwgZSkgOiBlLCBvID0gMDsgbnVsbCAhPSAociA9IGlbb10pOyBvKyspbiB8fCAxICE9PSByLm5vZGVUeXBlIHx8IHcuY2xlYW5EYXRhKHZlKHIpKSwgci5wYXJlbnROb2RlICYmIChuICYmIHcuY29udGFpbnMoci5vd25lckRvY3VtZW50LCByKSAmJiB5ZSh2ZShyLCAic2NyaXB0IikpLCByLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQocikpOyByZXR1cm4gZSB9IHcuZXh0ZW5kKHsgaHRtbFByZWZpbHRlcjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUucmVwbGFjZShEZSwgIjwkMT48LyQyPiIpIH0sIGNsb25lOiBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciwgaSwgbywgYSwgdSA9IGUuY2xvbmVOb2RlKCEwKSwgcyA9IHcuY29udGFpbnMoZS5vd25lckRvY3VtZW50LCBlKTsgaWYgKCEoaC5ub0Nsb25lQ2hlY2tlZCB8fCAxICE9PSBlLm5vZGVUeXBlICYmIDExICE9PSBlLm5vZGVUeXBlIHx8IHcuaXNYTUxEb2MoZSkpKSBmb3IgKGEgPSB2ZSh1KSwgciA9IDAsIGkgPSAobyA9IHZlKGUpKS5sZW5ndGg7IHIgPCBpOyByKyspSWUob1tyXSwgYVtyXSk7IGlmICh0KSBpZiAobikgZm9yIChvID0gbyB8fCB2ZShlKSwgYSA9IGEgfHwgdmUodSksIHIgPSAwLCBpID0gby5sZW5ndGg7IHIgPCBpOyByKyspSGUob1tyXSwgYVtyXSk7IGVsc2UgSGUoZSwgdSk7IHJldHVybiAoYSA9IHZlKHUsICJzY3JpcHQiKSkubGVuZ3RoID4gMCAmJiB5ZShhLCAhcyAmJiB2ZShlLCAic2NyaXB0IikpLCB1IH0sIGNsZWFuRGF0YTogZnVuY3Rpb24gKGUpIHsgZm9yICh2YXIgdCwgbiwgciwgaSA9IHcuZXZlbnQuc3BlY2lhbCwgbyA9IDA7IHZvaWQgMCAhPT0gKG4gPSBlW29dKTsgbysrKWlmIChZKG4pKSB7IGlmICh0ID0gbltLLmV4cGFuZG9dKSB7IGlmICh0LmV2ZW50cykgZm9yIChyIGluIHQuZXZlbnRzKSBpW3JdID8gdy5ldmVudC5yZW1vdmUobiwgcikgOiB3LnJlbW92ZUV2ZW50KG4sIHIsIHQuaGFuZGxlKTsgbltLLmV4cGFuZG9dID0gdm9pZCAwIH0gbltKLmV4cGFuZG9dICYmIChuW0ouZXhwYW5kb10gPSB2b2lkIDApIH0gfSB9KSwgdy5mbi5leHRlbmQoeyBkZXRhY2g6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBCZSh0aGlzLCBlLCAhMCkgfSwgcmVtb3ZlOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gQmUodGhpcywgZSkgfSwgdGV4dDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIF8odGhpcywgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHZvaWQgMCA9PT0gZSA/IHcudGV4dCh0aGlzKSA6IHRoaXMuZW1wdHkoKS5lYWNoKGZ1bmN0aW9uICgpIHsgMSAhPT0gdGhpcy5ub2RlVHlwZSAmJiAxMSAhPT0gdGhpcy5ub2RlVHlwZSAmJiA5ICE9PSB0aGlzLm5vZGVUeXBlIHx8ICh0aGlzLnRleHRDb250ZW50ID0gZSkgfSkgfSwgbnVsbCwgZSwgYXJndW1lbnRzLmxlbmd0aCkgfSwgYXBwZW5kOiBmdW5jdGlvbiAoKSB7IHJldHVybiBSZSh0aGlzLCBhcmd1bWVudHMsIGZ1bmN0aW9uIChlKSB7IDEgIT09IHRoaXMubm9kZVR5cGUgJiYgMTEgIT09IHRoaXMubm9kZVR5cGUgJiYgOSAhPT0gdGhpcy5ub2RlVHlwZSB8fCBxZSh0aGlzLCBlKS5hcHBlbmRDaGlsZChlKSB9KSB9LCBwcmVwZW5kOiBmdW5jdGlvbiAoKSB7IHJldHVybiBSZSh0aGlzLCBhcmd1bWVudHMsIGZ1bmN0aW9uIChlKSB7IGlmICgxID09PSB0aGlzLm5vZGVUeXBlIHx8IDExID09PSB0aGlzLm5vZGVUeXBlIHx8IDkgPT09IHRoaXMubm9kZVR5cGUpIHsgdmFyIHQgPSBxZSh0aGlzLCBlKTsgdC5pbnNlcnRCZWZvcmUoZSwgdC5maXJzdENoaWxkKSB9IH0pIH0sIGJlZm9yZTogZnVuY3Rpb24gKCkgeyByZXR1cm4gUmUodGhpcywgYXJndW1lbnRzLCBmdW5jdGlvbiAoZSkgeyB0aGlzLnBhcmVudE5vZGUgJiYgdGhpcy5wYXJlbnROb2RlLmluc2VydEJlZm9yZShlLCB0aGlzKSB9KSB9LCBhZnRlcjogZnVuY3Rpb24gKCkgeyByZXR1cm4gUmUodGhpcywgYXJndW1lbnRzLCBmdW5jdGlvbiAoZSkgeyB0aGlzLnBhcmVudE5vZGUgJiYgdGhpcy5wYXJlbnROb2RlLmluc2VydEJlZm9yZShlLCB0aGlzLm5leHRTaWJsaW5nKSB9KSB9LCBlbXB0eTogZnVuY3Rpb24gKCkgeyBmb3IgKHZhciBlLCB0ID0gMDsgbnVsbCAhPSAoZSA9IHRoaXNbdF0pOyB0KyspMSA9PT0gZS5ub2RlVHlwZSAmJiAody5jbGVhbkRhdGEodmUoZSwgITEpKSwgZS50ZXh0Q29udGVudCA9ICIiKTsgcmV0dXJuIHRoaXMgfSwgY2xvbmU6IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiBlID0gbnVsbCAhPSBlICYmIGUsIHQgPSBudWxsID09IHQgPyBlIDogdCwgdGhpcy5tYXAoZnVuY3Rpb24gKCkgeyByZXR1cm4gdy5jbG9uZSh0aGlzLCBlLCB0KSB9KSB9LCBodG1sOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gXyh0aGlzLCBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IHRoaXNbMF0gfHwge30sIG4gPSAwLCByID0gdGhpcy5sZW5ndGg7IGlmICh2b2lkIDAgPT09IGUgJiYgMSA9PT0gdC5ub2RlVHlwZSkgcmV0dXJuIHQuaW5uZXJIVE1MOyBpZiAoInN0cmluZyIgPT0gdHlwZW9mIGUgJiYgIVNlLnRlc3QoZSkgJiYgIWdlWyhwZS5leGVjKGUpIHx8IFsiIiwgIiJdKVsxXS50b0xvd2VyQ2FzZSgpXSkgeyBlID0gdy5odG1sUHJlZmlsdGVyKGUpOyB0cnkgeyBmb3IgKDsgbiA8IHI7IG4rKykxID09PSAodCA9IHRoaXNbbl0gfHwge30pLm5vZGVUeXBlICYmICh3LmNsZWFuRGF0YSh2ZSh0LCAhMSkpLCB0LmlubmVySFRNTCA9IGUpOyB0ID0gMCB9IGNhdGNoIChlKSB7IH0gfSB0ICYmIHRoaXMuZW1wdHkoKS5hcHBlbmQoZSkgfSwgbnVsbCwgZSwgYXJndW1lbnRzLmxlbmd0aCkgfSwgcmVwbGFjZVdpdGg6IGZ1bmN0aW9uICgpIHsgdmFyIGUgPSBbXTsgcmV0dXJuIFJlKHRoaXMsIGFyZ3VtZW50cywgZnVuY3Rpb24gKHQpIHsgdmFyIG4gPSB0aGlzLnBhcmVudE5vZGU7IHcuaW5BcnJheSh0aGlzLCBlKSA8IDAgJiYgKHcuY2xlYW5EYXRhKHZlKHRoaXMpKSwgbiAmJiBuLnJlcGxhY2VDaGlsZCh0LCB0aGlzKSkgfSwgZSkgfSB9KSwgdy5lYWNoKHsgYXBwZW5kVG86ICJhcHBlbmQiLCBwcmVwZW5kVG86ICJwcmVwZW5kIiwgaW5zZXJ0QmVmb3JlOiAiYmVmb3JlIiwgaW5zZXJ0QWZ0ZXI6ICJhZnRlciIsIHJlcGxhY2VBbGw6ICJyZXBsYWNlV2l0aCIgfSwgZnVuY3Rpb24gKGUsIHQpIHsgdy5mbltlXSA9IGZ1bmN0aW9uIChlKSB7IGZvciAodmFyIG4sIHIgPSBbXSwgaSA9IHcoZSksIG8gPSBpLmxlbmd0aCAtIDEsIGEgPSAwOyBhIDw9IG87IGErKyluID0gYSA9PT0gbyA/IHRoaXMgOiB0aGlzLmNsb25lKCEwKSwgdyhpW2FdKVt0XShuKSwgdS5hcHBseShyLCBuLmdldCgpKTsgcmV0dXJuIHRoaXMucHVzaFN0YWNrKHIpIH0gfSk7IHZhciBNZSA9IG5ldyBSZWdFeHAoIl4oIiArIHJlICsgIikoPyFweClbYS16JV0rJCIsICJpIiksIFdlID0gZnVuY3Rpb24gKHQpIHsgdmFyIG4gPSB0Lm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXc7IHJldHVybiBuICYmIG4ub3BlbmVyIHx8IChuID0gZSksIG4uZ2V0Q29tcHV0ZWRTdHlsZSh0KSB9LCAkZSA9IG5ldyBSZWdFeHAob2Uuam9pbigifCIpLCAiaSIpOyAhZnVuY3Rpb24gKCkgeyBmdW5jdGlvbiB0KCkgeyBpZiAoYykgeyBsLnN0eWxlLmNzc1RleHQgPSAicG9zaXRpb246YWJzb2x1dGU7bGVmdDotMTExMTFweDt3aWR0aDo2MHB4O21hcmdpbi10b3A6MXB4O3BhZGRpbmc6MDtib3JkZXI6MCIsIGMuc3R5bGUuY3NzVGV4dCA9ICJwb3NpdGlvbjpyZWxhdGl2ZTtkaXNwbGF5OmJsb2NrO2JveC1zaXppbmc6Ym9yZGVyLWJveDtvdmVyZmxvdzpzY3JvbGw7bWFyZ2luOmF1dG87Ym9yZGVyOjFweDtwYWRkaW5nOjFweDt3aWR0aDo2MCU7dG9wOjElIiwgeGUuYXBwZW5kQ2hpbGQobCkuYXBwZW5kQ2hpbGQoYyk7IHZhciB0ID0gZS5nZXRDb21wdXRlZFN0eWxlKGMpOyBpID0gIjElIiAhPT0gdC50b3AsIHMgPSAxMiA9PT0gbih0Lm1hcmdpbkxlZnQpLCBjLnN0eWxlLnJpZ2h0ID0gIjYwJSIsIHUgPSAzNiA9PT0gbih0LnJpZ2h0KSwgbyA9IDM2ID09PSBuKHQud2lkdGgpLCBjLnN0eWxlLnBvc2l0aW9uID0gImFic29sdXRlIiwgYSA9IDM2ID09PSBjLm9mZnNldFdpZHRoIHx8ICJhYnNvbHV0ZSIsIHhlLnJlbW92ZUNoaWxkKGwpLCBjID0gbnVsbCB9IH0gZnVuY3Rpb24gbihlKSB7IHJldHVybiBNYXRoLnJvdW5kKHBhcnNlRmxvYXQoZSkpIH0gdmFyIGksIG8sIGEsIHUsIHMsIGwgPSByLmNyZWF0ZUVsZW1lbnQoImRpdiIpLCBjID0gci5jcmVhdGVFbGVtZW50KCJkaXYiKTsgYy5zdHlsZSAmJiAoYy5zdHlsZS5iYWNrZ3JvdW5kQ2xpcCA9ICJjb250ZW50LWJveCIsIGMuY2xvbmVOb2RlKCEwKS5zdHlsZS5iYWNrZ3JvdW5kQ2xpcCA9ICIiLCBoLmNsZWFyQ2xvbmVTdHlsZSA9ICJjb250ZW50LWJveCIgPT09IGMuc3R5bGUuYmFja2dyb3VuZENsaXAsIHcuZXh0ZW5kKGgsIHsgYm94U2l6aW5nUmVsaWFibGU6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHQoKSwgbyB9LCBwaXhlbEJveFN0eWxlczogZnVuY3Rpb24gKCkgeyByZXR1cm4gdCgpLCB1IH0sIHBpeGVsUG9zaXRpb246IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHQoKSwgaSB9LCByZWxpYWJsZU1hcmdpbkxlZnQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHQoKSwgcyB9LCBzY3JvbGxib3hTaXplOiBmdW5jdGlvbiAoKSB7IHJldHVybiB0KCksIGEgfSB9KSkgfSgpOyBmdW5jdGlvbiBGZShlLCB0LCBuKSB7IHZhciByLCBpLCBvLCBhLCB1ID0gZS5zdHlsZTsgcmV0dXJuIChuID0gbiB8fCBXZShlKSkgJiYgKCIiICE9PSAoYSA9IG4uZ2V0UHJvcGVydHlWYWx1ZSh0KSB8fCBuW3RdKSB8fCB3LmNvbnRhaW5zKGUub3duZXJEb2N1bWVudCwgZSkgfHwgKGEgPSB3LnN0eWxlKGUsIHQpKSwgIWgucGl4ZWxCb3hTdHlsZXMoKSAmJiBNZS50ZXN0KGEpICYmICRlLnRlc3QodCkgJiYgKHIgPSB1LndpZHRoLCBpID0gdS5taW5XaWR0aCwgbyA9IHUubWF4V2lkdGgsIHUubWluV2lkdGggPSB1Lm1heFdpZHRoID0gdS53aWR0aCA9IGEsIGEgPSBuLndpZHRoLCB1LndpZHRoID0gciwgdS5taW5XaWR0aCA9IGksIHUubWF4V2lkdGggPSBvKSksIHZvaWQgMCAhPT0gYSA/IGEgKyAiIiA6IGEgfSBmdW5jdGlvbiB6ZShlLCB0KSB7IHJldHVybiB7IGdldDogZnVuY3Rpb24gKCkgeyBpZiAoIWUoKSkgcmV0dXJuICh0aGlzLmdldCA9IHQpLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IGRlbGV0ZSB0aGlzLmdldCB9IH0gfSB2YXIgX2UgPSAvXihub25lfHRhYmxlKD8hLWNbZWFdKS4rKS8sIFVlID0gL14tLS8sIFZlID0geyBwb3NpdGlvbjogImFic29sdXRlIiwgdmlzaWJpbGl0eTogImhpZGRlbiIsIGRpc3BsYXk6ICJibG9jayIgfSwgWGUgPSB7IGxldHRlclNwYWNpbmc6ICIwIiwgZm9udFdlaWdodDogIjQwMCIgfSwgUWUgPSBbIldlYmtpdCIsICJNb3oiLCAibXMiXSwgWWUgPSByLmNyZWF0ZUVsZW1lbnQoImRpdiIpLnN0eWxlOyBmdW5jdGlvbiBHZShlKSB7IGlmIChlIGluIFllKSByZXR1cm4gZTsgdmFyIHQgPSBlWzBdLnRvVXBwZXJDYXNlKCkgKyBlLnNsaWNlKDEpLCBuID0gUWUubGVuZ3RoOyB3aGlsZSAobi0tKSBpZiAoKGUgPSBRZVtuXSArIHQpIGluIFllKSByZXR1cm4gZSB9IGZ1bmN0aW9uIEtlKGUpIHsgdmFyIHQgPSB3LmNzc1Byb3BzW2VdOyByZXR1cm4gdCB8fCAodCA9IHcuY3NzUHJvcHNbZV0gPSBHZShlKSB8fCBlKSwgdCB9IGZ1bmN0aW9uIEplKGUsIHQsIG4pIHsgdmFyIHIgPSBpZS5leGVjKHQpOyByZXR1cm4gciA/IE1hdGgubWF4KDAsIHJbMl0gLSAobiB8fCAwKSkgKyAoclszXSB8fCAicHgiKSA6IHQgfSBmdW5jdGlvbiBaZShlLCB0LCBuLCByLCBpLCBvKSB7IHZhciBhID0gIndpZHRoIiA9PT0gdCA/IDEgOiAwLCB1ID0gMCwgcyA9IDA7IGlmIChuID09PSAociA/ICJib3JkZXIiIDogImNvbnRlbnQiKSkgcmV0dXJuIDA7IGZvciAoOyBhIDwgNDsgYSArPSAyKSJtYXJnaW4iID09PSBuICYmIChzICs9IHcuY3NzKGUsIG4gKyBvZVthXSwgITAsIGkpKSwgciA/ICgiY29udGVudCIgPT09IG4gJiYgKHMgLT0gdy5jc3MoZSwgInBhZGRpbmciICsgb2VbYV0sICEwLCBpKSksICJtYXJnaW4iICE9PSBuICYmIChzIC09IHcuY3NzKGUsICJib3JkZXIiICsgb2VbYV0gKyAiV2lkdGgiLCAhMCwgaSkpKSA6IChzICs9IHcuY3NzKGUsICJwYWRkaW5nIiArIG9lW2FdLCAhMCwgaSksICJwYWRkaW5nIiAhPT0gbiA/IHMgKz0gdy5jc3MoZSwgImJvcmRlciIgKyBvZVthXSArICJXaWR0aCIsICEwLCBpKSA6IHUgKz0gdy5jc3MoZSwgImJvcmRlciIgKyBvZVthXSArICJXaWR0aCIsICEwLCBpKSk7IHJldHVybiAhciAmJiBvID49IDAgJiYgKHMgKz0gTWF0aC5tYXgoMCwgTWF0aC5jZWlsKGVbIm9mZnNldCIgKyB0WzBdLnRvVXBwZXJDYXNlKCkgKyB0LnNsaWNlKDEpXSAtIG8gLSBzIC0gdSAtIC41KSkpLCBzIH0gZnVuY3Rpb24gZXQoZSwgdCwgbikgeyB2YXIgciA9IFdlKGUpLCBpID0gRmUoZSwgdCwgciksIG8gPSAiYm9yZGVyLWJveCIgPT09IHcuY3NzKGUsICJib3hTaXppbmciLCAhMSwgciksIGEgPSBvOyBpZiAoTWUudGVzdChpKSkgeyBpZiAoIW4pIHJldHVybiBpOyBpID0gImF1dG8iIH0gcmV0dXJuIGEgPSBhICYmIChoLmJveFNpemluZ1JlbGlhYmxlKCkgfHwgaSA9PT0gZS5zdHlsZVt0XSksICgiYXV0byIgPT09IGkgfHwgIXBhcnNlRmxvYXQoaSkgJiYgImlubGluZSIgPT09IHcuY3NzKGUsICJkaXNwbGF5IiwgITEsIHIpKSAmJiAoaSA9IGVbIm9mZnNldCIgKyB0WzBdLnRvVXBwZXJDYXNlKCkgKyB0LnNsaWNlKDEpXSwgYSA9ICEwKSwgKGkgPSBwYXJzZUZsb2F0KGkpIHx8IDApICsgWmUoZSwgdCwgbiB8fCAobyA/ICJib3JkZXIiIDogImNvbnRlbnQiKSwgYSwgciwgaSkgKyAicHgiIH0gdy5leHRlbmQoeyBjc3NIb29rczogeyBvcGFjaXR5OiB7IGdldDogZnVuY3Rpb24gKGUsIHQpIHsgaWYgKHQpIHsgdmFyIG4gPSBGZShlLCAib3BhY2l0eSIpOyByZXR1cm4gIiIgPT09IG4gPyAiMSIgOiBuIH0gfSB9IH0sIGNzc051bWJlcjogeyBhbmltYXRpb25JdGVyYXRpb25Db3VudDogITAsIGNvbHVtbkNvdW50OiAhMCwgZmlsbE9wYWNpdHk6ICEwLCBmbGV4R3JvdzogITAsIGZsZXhTaHJpbms6ICEwLCBmb250V2VpZ2h0OiAhMCwgbGluZUhlaWdodDogITAsIG9wYWNpdHk6ICEwLCBvcmRlcjogITAsIG9ycGhhbnM6ICEwLCB3aWRvd3M6ICEwLCB6SW5kZXg6ICEwLCB6b29tOiAhMCB9LCBjc3NQcm9wczoge30sIHN0eWxlOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyBpZiAoZSAmJiAzICE9PSBlLm5vZGVUeXBlICYmIDggIT09IGUubm9kZVR5cGUgJiYgZS5zdHlsZSkgeyB2YXIgaSwgbywgYSwgdSA9IFEodCksIHMgPSBVZS50ZXN0KHQpLCBsID0gZS5zdHlsZTsgaWYgKHMgfHwgKHQgPSBLZSh1KSksIGEgPSB3LmNzc0hvb2tzW3RdIHx8IHcuY3NzSG9va3NbdV0sIHZvaWQgMCA9PT0gbikgcmV0dXJuIGEgJiYgImdldCIgaW4gYSAmJiB2b2lkIDAgIT09IChpID0gYS5nZXQoZSwgITEsIHIpKSA/IGkgOiBsW3RdOyAic3RyaW5nIiA9PSAobyA9IHR5cGVvZiBuKSAmJiAoaSA9IGllLmV4ZWMobikpICYmIGlbMV0gJiYgKG4gPSBzZShlLCB0LCBpKSwgbyA9ICJudW1iZXIiKSwgbnVsbCAhPSBuICYmIG4gPT09IG4gJiYgKCJudW1iZXIiID09PSBvICYmIChuICs9IGkgJiYgaVszXSB8fCAody5jc3NOdW1iZXJbdV0gPyAiIiA6ICJweCIpKSwgaC5jbGVhckNsb25lU3R5bGUgfHwgIiIgIT09IG4gfHwgMCAhPT0gdC5pbmRleE9mKCJiYWNrZ3JvdW5kIikgfHwgKGxbdF0gPSAiaW5oZXJpdCIpLCBhICYmICJzZXQiIGluIGEgJiYgdm9pZCAwID09PSAobiA9IGEuc2V0KGUsIG4sIHIpKSB8fCAocyA/IGwuc2V0UHJvcGVydHkodCwgbikgOiBsW3RdID0gbikpIH0gfSwgY3NzOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyB2YXIgaSwgbywgYSwgdSA9IFEodCk7IHJldHVybiBVZS50ZXN0KHQpIHx8ICh0ID0gS2UodSkpLCAoYSA9IHcuY3NzSG9va3NbdF0gfHwgdy5jc3NIb29rc1t1XSkgJiYgImdldCIgaW4gYSAmJiAoaSA9IGEuZ2V0KGUsICEwLCBuKSksIHZvaWQgMCA9PT0gaSAmJiAoaSA9IEZlKGUsIHQsIHIpKSwgIm5vcm1hbCIgPT09IGkgJiYgdCBpbiBYZSAmJiAoaSA9IFhlW3RdKSwgIiIgPT09IG4gfHwgbiA/IChvID0gcGFyc2VGbG9hdChpKSwgITAgPT09IG4gfHwgaXNGaW5pdGUobykgPyBvIHx8IDAgOiBpKSA6IGkgfSB9KSwgdy5lYWNoKFsiaGVpZ2h0IiwgIndpZHRoIl0sIGZ1bmN0aW9uIChlLCB0KSB7IHcuY3NzSG9va3NbdF0gPSB7IGdldDogZnVuY3Rpb24gKGUsIG4sIHIpIHsgaWYgKG4pIHJldHVybiAhX2UudGVzdCh3LmNzcyhlLCAiZGlzcGxheSIpKSB8fCBlLmdldENsaWVudFJlY3RzKCkubGVuZ3RoICYmIGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGggPyBldChlLCB0LCByKSA6IHVlKGUsIFZlLCBmdW5jdGlvbiAoKSB7IHJldHVybiBldChlLCB0LCByKSB9KSB9LCBzZXQ6IGZ1bmN0aW9uIChlLCBuLCByKSB7IHZhciBpLCBvID0gV2UoZSksIGEgPSAiYm9yZGVyLWJveCIgPT09IHcuY3NzKGUsICJib3hTaXppbmciLCAhMSwgbyksIHUgPSByICYmIFplKGUsIHQsIHIsIGEsIG8pOyByZXR1cm4gYSAmJiBoLnNjcm9sbGJveFNpemUoKSA9PT0gby5wb3NpdGlvbiAmJiAodSAtPSBNYXRoLmNlaWwoZVsib2Zmc2V0IiArIHRbMF0udG9VcHBlckNhc2UoKSArIHQuc2xpY2UoMSldIC0gcGFyc2VGbG9hdChvW3RdKSAtIFplKGUsIHQsICJib3JkZXIiLCAhMSwgbykgLSAuNSkpLCB1ICYmIChpID0gaWUuZXhlYyhuKSkgJiYgInB4IiAhPT0gKGlbM10gfHwgInB4IikgJiYgKGUuc3R5bGVbdF0gPSBuLCBuID0gdy5jc3MoZSwgdCkpLCBKZShlLCBuLCB1KSB9IH0gfSksIHcuY3NzSG9va3MubWFyZ2luTGVmdCA9IHplKGgucmVsaWFibGVNYXJnaW5MZWZ0LCBmdW5jdGlvbiAoZSwgdCkgeyBpZiAodCkgcmV0dXJuIChwYXJzZUZsb2F0KEZlKGUsICJtYXJnaW5MZWZ0IikpIHx8IGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkubGVmdCAtIHVlKGUsIHsgbWFyZ2luTGVmdDogMCB9LCBmdW5jdGlvbiAoKSB7IHJldHVybiBlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQgfSkpICsgInB4IiB9KSwgdy5lYWNoKHsgbWFyZ2luOiAiIiwgcGFkZGluZzogIiIsIGJvcmRlcjogIldpZHRoIiB9LCBmdW5jdGlvbiAoZSwgdCkgeyB3LmNzc0hvb2tzW2UgKyB0XSA9IHsgZXhwYW5kOiBmdW5jdGlvbiAobikgeyBmb3IgKHZhciByID0gMCwgaSA9IHt9LCBvID0gInN0cmluZyIgPT0gdHlwZW9mIG4gPyBuLnNwbGl0KCIgIikgOiBbbl07IHIgPCA0OyByKyspaVtlICsgb2Vbcl0gKyB0XSA9IG9bcl0gfHwgb1tyIC0gMl0gfHwgb1swXTsgcmV0dXJuIGkgfSB9LCAibWFyZ2luIiAhPT0gZSAmJiAody5jc3NIb29rc1tlICsgdF0uc2V0ID0gSmUpIH0pLCB3LmZuLmV4dGVuZCh7IGNzczogZnVuY3Rpb24gKGUsIHQpIHsgcmV0dXJuIF8odGhpcywgZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIsIGksIG8gPSB7fSwgYSA9IDA7IGlmIChBcnJheS5pc0FycmF5KHQpKSB7IGZvciAociA9IFdlKGUpLCBpID0gdC5sZW5ndGg7IGEgPCBpOyBhKyspb1t0W2FdXSA9IHcuY3NzKGUsIHRbYV0sICExLCByKTsgcmV0dXJuIG8gfSByZXR1cm4gdm9pZCAwICE9PSBuID8gdy5zdHlsZShlLCB0LCBuKSA6IHcuY3NzKGUsIHQpIH0sIGUsIHQsIGFyZ3VtZW50cy5sZW5ndGggPiAxKSB9IH0pLCB3LmZuLmRlbGF5ID0gZnVuY3Rpb24gKHQsIG4pIHsgcmV0dXJuIHQgPSB3LmZ4ID8gdy5meC5zcGVlZHNbdF0gfHwgdCA6IHQsIG4gPSBuIHx8ICJmeCIsIHRoaXMucXVldWUobiwgZnVuY3Rpb24gKG4sIHIpIHsgdmFyIGkgPSBlLnNldFRpbWVvdXQobiwgdCk7IHIuc3RvcCA9IGZ1bmN0aW9uICgpIHsgZS5jbGVhclRpbWVvdXQoaSkgfSB9KSB9LCBmdW5jdGlvbiAoKSB7IHZhciBlID0gci5jcmVhdGVFbGVtZW50KCJpbnB1dCIpLCB0ID0gci5jcmVhdGVFbGVtZW50KCJzZWxlY3QiKS5hcHBlbmRDaGlsZChyLmNyZWF0ZUVsZW1lbnQoIm9wdGlvbiIpKTsgZS50eXBlID0gImNoZWNrYm94IiwgaC5jaGVja09uID0gIiIgIT09IGUudmFsdWUsIGgub3B0U2VsZWN0ZWQgPSB0LnNlbGVjdGVkLCAoZSA9IHIuY3JlYXRlRWxlbWVudCgiaW5wdXQiKSkudmFsdWUgPSAidCIsIGUudHlwZSA9ICJyYWRpbyIsIGgucmFkaW9WYWx1ZSA9ICJ0IiA9PT0gZS52YWx1ZSB9KCk7IHZhciB0dCwgbnQgPSB3LmV4cHIuYXR0ckhhbmRsZTsgdy5mbi5leHRlbmQoeyBhdHRyOiBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gXyh0aGlzLCB3LmF0dHIsIGUsIHQsIGFyZ3VtZW50cy5sZW5ndGggPiAxKSB9LCByZW1vdmVBdHRyOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgdy5yZW1vdmVBdHRyKHRoaXMsIGUpIH0pIH0gfSksIHcuZXh0ZW5kKHsgYXR0cjogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIsIGksIG8gPSBlLm5vZGVUeXBlOyBpZiAoMyAhPT0gbyAmJiA4ICE9PSBvICYmIDIgIT09IG8pIHJldHVybiAidW5kZWZpbmVkIiA9PSB0eXBlb2YgZS5nZXRBdHRyaWJ1dGUgPyB3LnByb3AoZSwgdCwgbikgOiAoMSA9PT0gbyAmJiB3LmlzWE1MRG9jKGUpIHx8IChpID0gdy5hdHRySG9va3NbdC50b0xvd2VyQ2FzZSgpXSB8fCAody5leHByLm1hdGNoLmJvb2wudGVzdCh0KSA/IHR0IDogdm9pZCAwKSksIHZvaWQgMCAhPT0gbiA/IG51bGwgPT09IG4gPyB2b2lkIHcucmVtb3ZlQXR0cihlLCB0KSA6IGkgJiYgInNldCIgaW4gaSAmJiB2b2lkIDAgIT09IChyID0gaS5zZXQoZSwgbiwgdCkpID8gciA6IChlLnNldEF0dHJpYnV0ZSh0LCBuICsgIiIpLCBuKSA6IGkgJiYgImdldCIgaW4gaSAmJiBudWxsICE9PSAociA9IGkuZ2V0KGUsIHQpKSA/IHIgOiBudWxsID09IChyID0gdy5maW5kLmF0dHIoZSwgdCkpID8gdm9pZCAwIDogcikgfSwgYXR0ckhvb2tzOiB7IHR5cGU6IHsgc2V0OiBmdW5jdGlvbiAoZSwgdCkgeyBpZiAoIWgucmFkaW9WYWx1ZSAmJiAicmFkaW8iID09PSB0ICYmIEQoZSwgImlucHV0IikpIHsgdmFyIG4gPSBlLnZhbHVlOyByZXR1cm4gZS5zZXRBdHRyaWJ1dGUoInR5cGUiLCB0KSwgbiAmJiAoZS52YWx1ZSA9IG4pLCB0IH0gfSB9IH0sIHJlbW92ZUF0dHI6IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCByID0gMCwgaSA9IHQgJiYgdC5tYXRjaChJKTsgaWYgKGkgJiYgMSA9PT0gZS5ub2RlVHlwZSkgd2hpbGUgKG4gPSBpW3IrK10pIGUucmVtb3ZlQXR0cmlidXRlKG4pIH0gfSksIHR0ID0geyBzZXQ6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiAhMSA9PT0gdCA/IHcucmVtb3ZlQXR0cihlLCBuKSA6IGUuc2V0QXR0cmlidXRlKG4sIG4pLCBuIH0gfSwgdy5lYWNoKHcuZXhwci5tYXRjaC5ib29sLnNvdXJjZS5tYXRjaCgvXHcrL2cpLCBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IG50W3RdIHx8IHcuZmluZC5hdHRyOyBudFt0XSA9IGZ1bmN0aW9uIChlLCB0LCByKSB7IHZhciBpLCBvLCBhID0gdC50b0xvd2VyQ2FzZSgpOyByZXR1cm4gciB8fCAobyA9IG50W2FdLCBudFthXSA9IGksIGkgPSBudWxsICE9IG4oZSwgdCwgcikgPyBhIDogbnVsbCwgbnRbYV0gPSBvKSwgaSB9IH0pOyB2YXIgcnQgPSAvXig/OmlucHV0fHNlbGVjdHx0ZXh0YXJlYXxidXR0b24pJC9pLCBpdCA9IC9eKD86YXxhcmVhKSQvaTsgdy5mbi5leHRlbmQoeyBwcm9wOiBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gXyh0aGlzLCB3LnByb3AsIGUsIHQsIGFyZ3VtZW50cy5sZW5ndGggPiAxKSB9LCByZW1vdmVQcm9wOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgZGVsZXRlIHRoaXNbdy5wcm9wRml4W2VdIHx8IGVdIH0pIH0gfSksIHcuZXh0ZW5kKHsgcHJvcDogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIsIGksIG8gPSBlLm5vZGVUeXBlOyBpZiAoMyAhPT0gbyAmJiA4ICE9PSBvICYmIDIgIT09IG8pIHJldHVybiAxID09PSBvICYmIHcuaXNYTUxEb2MoZSkgfHwgKHQgPSB3LnByb3BGaXhbdF0gfHwgdCwgaSA9IHcucHJvcEhvb2tzW3RdKSwgdm9pZCAwICE9PSBuID8gaSAmJiAic2V0IiBpbiBpICYmIHZvaWQgMCAhPT0gKHIgPSBpLnNldChlLCBuLCB0KSkgPyByIDogZVt0XSA9IG4gOiBpICYmICJnZXQiIGluIGkgJiYgbnVsbCAhPT0gKHIgPSBpLmdldChlLCB0KSkgPyByIDogZVt0XSB9LCBwcm9wSG9va3M6IHsgdGFiSW5kZXg6IHsgZ2V0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IHcuZmluZC5hdHRyKGUsICJ0YWJpbmRleCIpOyByZXR1cm4gdCA/IHBhcnNlSW50KHQsIDEwKSA6IHJ0LnRlc3QoZS5ub2RlTmFtZSkgfHwgaXQudGVzdChlLm5vZGVOYW1lKSAmJiBlLmhyZWYgPyAwIDogLTEgfSB9IH0sIHByb3BGaXg6IHsgImZvciI6ICJodG1sRm9yIiwgImNsYXNzIjogImNsYXNzTmFtZSIgfSB9KSwgaC5vcHRTZWxlY3RlZCB8fCAody5wcm9wSG9va3Muc2VsZWN0ZWQgPSB7IGdldDogZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSBlLnBhcmVudE5vZGU7IHJldHVybiB0ICYmIHQucGFyZW50Tm9kZSAmJiB0LnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleCwgbnVsbCB9LCBzZXQ6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZS5wYXJlbnROb2RlOyB0ICYmICh0LnNlbGVjdGVkSW5kZXgsIHQucGFyZW50Tm9kZSAmJiB0LnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleCkgfSB9KSwgdy5lYWNoKFsidGFiSW5kZXgiLCAicmVhZE9ubHkiLCAibWF4TGVuZ3RoIiwgImNlbGxTcGFjaW5nIiwgImNlbGxQYWRkaW5nIiwgInJvd1NwYW4iLCAiY29sU3BhbiIsICJ1c2VNYXAiLCAiZnJhbWVCb3JkZXIiLCAiY29udGVudEVkaXRhYmxlIl0sIGZ1bmN0aW9uICgpIHsgdy5wcm9wRml4W3RoaXMudG9Mb3dlckNhc2UoKV0gPSB0aGlzIH0pOyBmdW5jdGlvbiBvdChlKSB7IHJldHVybiAoZS5tYXRjaChJKSB8fCBbXSkuam9pbigiICIpIH0gZnVuY3Rpb24gYXQoZSkgeyByZXR1cm4gZS5nZXRBdHRyaWJ1dGUgJiYgZS5nZXRBdHRyaWJ1dGUoImNsYXNzIikgfHwgIiIgfSBmdW5jdGlvbiB1dChlKSB7IHJldHVybiBBcnJheS5pc0FycmF5KGUpID8gZSA6ICJzdHJpbmciID09IHR5cGVvZiBlID8gZS5tYXRjaChJKSB8fCBbXSA6IFtdIH0gdy5mbi5leHRlbmQoeyBhZGRDbGFzczogZnVuY3Rpb24gKGUpIHsgdmFyIHQsIG4sIHIsIGksIG8sIGEsIHUsIHMgPSAwOyBpZiAoZyhlKSkgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAodCkgeyB3KHRoaXMpLmFkZENsYXNzKGUuY2FsbCh0aGlzLCB0LCBhdCh0aGlzKSkpIH0pOyBpZiAoKHQgPSB1dChlKSkubGVuZ3RoKSB3aGlsZSAobiA9IHRoaXNbcysrXSkgaWYgKGkgPSBhdChuKSwgciA9IDEgPT09IG4ubm9kZVR5cGUgJiYgIiAiICsgb3QoaSkgKyAiICIpIHsgYSA9IDA7IHdoaWxlIChvID0gdFthKytdKSByLmluZGV4T2YoIiAiICsgbyArICIgIikgPCAwICYmIChyICs9IG8gKyAiICIpOyBpICE9PSAodSA9IG90KHIpKSAmJiBuLnNldEF0dHJpYnV0ZSgiY2xhc3MiLCB1KSB9IHJldHVybiB0aGlzIH0sIHJlbW92ZUNsYXNzOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgbiwgciwgaSwgbywgYSwgdSwgcyA9IDA7IGlmIChnKGUpKSByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICh0KSB7IHcodGhpcykucmVtb3ZlQ2xhc3MoZS5jYWxsKHRoaXMsIHQsIGF0KHRoaXMpKSkgfSk7IGlmICghYXJndW1lbnRzLmxlbmd0aCkgcmV0dXJuIHRoaXMuYXR0cigiY2xhc3MiLCAiIik7IGlmICgodCA9IHV0KGUpKS5sZW5ndGgpIHdoaWxlIChuID0gdGhpc1tzKytdKSBpZiAoaSA9IGF0KG4pLCByID0gMSA9PT0gbi5ub2RlVHlwZSAmJiAiICIgKyBvdChpKSArICIgIikgeyBhID0gMDsgd2hpbGUgKG8gPSB0W2ErK10pIHdoaWxlIChyLmluZGV4T2YoIiAiICsgbyArICIgIikgPiAtMSkgciA9IHIucmVwbGFjZSgiICIgKyBvICsgIiAiLCAiICIpOyBpICE9PSAodSA9IG90KHIpKSAmJiBuLnNldEF0dHJpYnV0ZSgiY2xhc3MiLCB1KSB9IHJldHVybiB0aGlzIH0sIHRvZ2dsZUNsYXNzOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IHR5cGVvZiBlLCByID0gInN0cmluZyIgPT09IG4gfHwgQXJyYXkuaXNBcnJheShlKTsgcmV0dXJuICJib29sZWFuIiA9PSB0eXBlb2YgdCAmJiByID8gdCA/IHRoaXMuYWRkQ2xhc3MoZSkgOiB0aGlzLnJlbW92ZUNsYXNzKGUpIDogZyhlKSA/IHRoaXMuZWFjaChmdW5jdGlvbiAobikgeyB3KHRoaXMpLnRvZ2dsZUNsYXNzKGUuY2FsbCh0aGlzLCBuLCBhdCh0aGlzKSwgdCksIHQpIH0pIDogdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgdmFyIHQsIGksIG8sIGE7IGlmIChyKSB7IGkgPSAwLCBvID0gdyh0aGlzKSwgYSA9IHV0KGUpOyB3aGlsZSAodCA9IGFbaSsrXSkgby5oYXNDbGFzcyh0KSA/IG8ucmVtb3ZlQ2xhc3ModCkgOiBvLmFkZENsYXNzKHQpIH0gZWxzZSB2b2lkIDAgIT09IGUgJiYgImJvb2xlYW4iICE9PSBuIHx8ICgodCA9IGF0KHRoaXMpKSAmJiBLLnNldCh0aGlzLCAiX19jbGFzc05hbWVfXyIsIHQpLCB0aGlzLnNldEF0dHJpYnV0ZSAmJiB0aGlzLnNldEF0dHJpYnV0ZSgiY2xhc3MiLCB0IHx8ICExID09PSBlID8gIiIgOiBLLmdldCh0aGlzLCAiX19jbGFzc05hbWVfXyIpIHx8ICIiKSkgfSkgfSwgaGFzQ2xhc3M6IGZ1bmN0aW9uIChlKSB7IHZhciB0LCBuLCByID0gMDsgdCA9ICIgIiArIGUgKyAiICI7IHdoaWxlIChuID0gdGhpc1tyKytdKSBpZiAoMSA9PT0gbi5ub2RlVHlwZSAmJiAoIiAiICsgb3QoYXQobikpICsgIiAiKS5pbmRleE9mKHQpID4gLTEpIHJldHVybiAhMDsgcmV0dXJuICExIH0gfSk7IHZhciBzdCA9IC9cci9nOyB3LmZuLmV4dGVuZCh7IHZhbDogZnVuY3Rpb24gKGUpIHsgdmFyIHQsIG4sIHIsIGkgPSB0aGlzWzBdOyB7IGlmIChhcmd1bWVudHMubGVuZ3RoKSByZXR1cm4gciA9IGcoZSksIHRoaXMuZWFjaChmdW5jdGlvbiAobikgeyB2YXIgaTsgMSA9PT0gdGhpcy5ub2RlVHlwZSAmJiAobnVsbCA9PSAoaSA9IHIgPyBlLmNhbGwodGhpcywgbiwgdyh0aGlzKS52YWwoKSkgOiBlKSA/IGkgPSAiIiA6ICJudW1iZXIiID09IHR5cGVvZiBpID8gaSArPSAiIiA6IEFycmF5LmlzQXJyYXkoaSkgJiYgKGkgPSB3Lm1hcChpLCBmdW5jdGlvbiAoZSkgeyByZXR1cm4gbnVsbCA9PSBlID8gIiIgOiBlICsgIiIgfSkpLCAodCA9IHcudmFsSG9va3NbdGhpcy50eXBlXSB8fCB3LnZhbEhvb2tzW3RoaXMubm9kZU5hbWUudG9Mb3dlckNhc2UoKV0pICYmICJzZXQiIGluIHQgJiYgdm9pZCAwICE9PSB0LnNldCh0aGlzLCBpLCAidmFsdWUiKSB8fCAodGhpcy52YWx1ZSA9IGkpKSB9KTsgaWYgKGkpIHJldHVybiAodCA9IHcudmFsSG9va3NbaS50eXBlXSB8fCB3LnZhbEhvb2tzW2kubm9kZU5hbWUudG9Mb3dlckNhc2UoKV0pICYmICJnZXQiIGluIHQgJiYgdm9pZCAwICE9PSAobiA9IHQuZ2V0KGksICJ2YWx1ZSIpKSA/IG4gOiAic3RyaW5nIiA9PSB0eXBlb2YgKG4gPSBpLnZhbHVlKSA/IG4ucmVwbGFjZShzdCwgIiIpIDogbnVsbCA9PSBuID8gIiIgOiBuIH0gfSB9KSwgdy5leHRlbmQoeyB2YWxIb29rczogeyBvcHRpb246IHsgZ2V0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IHcuZmluZC5hdHRyKGUsICJ2YWx1ZSIpOyByZXR1cm4gbnVsbCAhPSB0ID8gdCA6IG90KHcudGV4dChlKSkgfSB9LCBzZWxlY3Q6IHsgZ2V0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgbiwgciwgaSA9IGUub3B0aW9ucywgbyA9IGUuc2VsZWN0ZWRJbmRleCwgYSA9ICJzZWxlY3Qtb25lIiA9PT0gZS50eXBlLCB1ID0gYSA/IG51bGwgOiBbXSwgcyA9IGEgPyBvICsgMSA6IGkubGVuZ3RoOyBmb3IgKHIgPSBvIDwgMCA/IHMgOiBhID8gbyA6IDA7IHIgPCBzOyByKyspaWYgKCgobiA9IGlbcl0pLnNlbGVjdGVkIHx8IHIgPT09IG8pICYmICFuLmRpc2FibGVkICYmICghbi5wYXJlbnROb2RlLmRpc2FibGVkIHx8ICFEKG4ucGFyZW50Tm9kZSwgIm9wdGdyb3VwIikpKSB7IGlmICh0ID0gdyhuKS52YWwoKSwgYSkgcmV0dXJuIHQ7IHUucHVzaCh0KSB9IHJldHVybiB1IH0sIHNldDogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIsIGkgPSBlLm9wdGlvbnMsIG8gPSB3Lm1ha2VBcnJheSh0KSwgYSA9IGkubGVuZ3RoOyB3aGlsZSAoYS0tKSAoKHIgPSBpW2FdKS5zZWxlY3RlZCA9IHcuaW5BcnJheSh3LnZhbEhvb2tzLm9wdGlvbi5nZXQociksIG8pID4gLTEpICYmIChuID0gITApOyByZXR1cm4gbiB8fCAoZS5zZWxlY3RlZEluZGV4ID0gLTEpLCBvIH0gfSB9IH0pLCB3LmVhY2goWyJyYWRpbyIsICJjaGVja2JveCJdLCBmdW5jdGlvbiAoKSB7IHcudmFsSG9va3NbdGhpc10gPSB7IHNldDogZnVuY3Rpb24gKGUsIHQpIHsgaWYgKEFycmF5LmlzQXJyYXkodCkpIHJldHVybiBlLmNoZWNrZWQgPSB3LmluQXJyYXkodyhlKS52YWwoKSwgdCkgPiAtMSB9IH0sIGguY2hlY2tPbiB8fCAody52YWxIb29rc1t0aGlzXS5nZXQgPSBmdW5jdGlvbiAoZSkgeyByZXR1cm4gbnVsbCA9PT0gZS5nZXRBdHRyaWJ1dGUoInZhbHVlIikgPyAib24iIDogZS52YWx1ZSB9KSB9KSwgaC5mb2N1c2luID0gIm9uZm9jdXNpbiIgaW4gZTsgdmFyIGx0ID0gL14oPzpmb2N1c2luZm9jdXN8Zm9jdXNvdXRibHVyKSQvLCBjdCA9IGZ1bmN0aW9uIChlKSB7IGUuc3RvcFByb3BhZ2F0aW9uKCkgfTsgdy5leHRlbmQody5ldmVudCwgeyB0cmlnZ2VyOiBmdW5jdGlvbiAodCwgbiwgaSwgbykgeyB2YXIgYSwgdSwgcywgbCwgYywgZCwgcCwgaCwgeSA9IFtpIHx8IHJdLCBtID0gZi5jYWxsKHQsICJ0eXBlIikgPyB0LnR5cGUgOiB0LCBiID0gZi5jYWxsKHQsICJuYW1lc3BhY2UiKSA/IHQubmFtZXNwYWNlLnNwbGl0KCIuIikgOiBbXTsgaWYgKHUgPSBoID0gcyA9IGkgPSBpIHx8IHIsIDMgIT09IGkubm9kZVR5cGUgJiYgOCAhPT0gaS5ub2RlVHlwZSAmJiAhbHQudGVzdChtICsgdy5ldmVudC50cmlnZ2VyZWQpICYmIChtLmluZGV4T2YoIi4iKSA+IC0xICYmIChtID0gKGIgPSBtLnNwbGl0KCIuIikpLnNoaWZ0KCksIGIuc29ydCgpKSwgYyA9IG0uaW5kZXhPZigiOiIpIDwgMCAmJiAib24iICsgbSwgdCA9IHRbdy5leHBhbmRvXSA/IHQgOiBuZXcgdy5FdmVudChtLCAib2JqZWN0IiA9PSB0eXBlb2YgdCAmJiB0KSwgdC5pc1RyaWdnZXIgPSBvID8gMiA6IDMsIHQubmFtZXNwYWNlID0gYi5qb2luKCIuIiksIHQucm5hbWVzcGFjZSA9IHQubmFtZXNwYWNlID8gbmV3IFJlZ0V4cCgiKF58XFwuKSIgKyBiLmpvaW4oIlxcLig/Oi4qXFwufCkiKSArICIoXFwufCQpIikgOiBudWxsLCB0LnJlc3VsdCA9IHZvaWQgMCwgdC50YXJnZXQgfHwgKHQudGFyZ2V0ID0gaSksIG4gPSBudWxsID09IG4gPyBbdF0gOiB3Lm1ha2VBcnJheShuLCBbdF0pLCBwID0gdy5ldmVudC5zcGVjaWFsW21dIHx8IHt9LCBvIHx8ICFwLnRyaWdnZXIgfHwgITEgIT09IHAudHJpZ2dlci5hcHBseShpLCBuKSkpIHsgaWYgKCFvICYmICFwLm5vQnViYmxlICYmICF2KGkpKSB7IGZvciAobCA9IHAuZGVsZWdhdGVUeXBlIHx8IG0sIGx0LnRlc3QobCArIG0pIHx8ICh1ID0gdS5wYXJlbnROb2RlKTsgdTsgdSA9IHUucGFyZW50Tm9kZSl5LnB1c2godSksIHMgPSB1OyBzID09PSAoaS5vd25lckRvY3VtZW50IHx8IHIpICYmIHkucHVzaChzLmRlZmF1bHRWaWV3IHx8IHMucGFyZW50V2luZG93IHx8IGUpIH0gYSA9IDA7IHdoaWxlICgodSA9IHlbYSsrXSkgJiYgIXQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSkgaCA9IHUsIHQudHlwZSA9IGEgPiAxID8gbCA6IHAuYmluZFR5cGUgfHwgbSwgKGQgPSAoSy5nZXQodSwgImV2ZW50cyIpIHx8IHt9KVt0LnR5cGVdICYmIEsuZ2V0KHUsICJoYW5kbGUiKSkgJiYgZC5hcHBseSh1LCBuKSwgKGQgPSBjICYmIHVbY10pICYmIGQuYXBwbHkgJiYgWSh1KSAmJiAodC5yZXN1bHQgPSBkLmFwcGx5KHUsIG4pLCAhMSA9PT0gdC5yZXN1bHQgJiYgdC5wcmV2ZW50RGVmYXVsdCgpKTsgcmV0dXJuIHQudHlwZSA9IG0sIG8gfHwgdC5pc0RlZmF1bHRQcmV2ZW50ZWQoKSB8fCBwLl9kZWZhdWx0ICYmICExICE9PSBwLl9kZWZhdWx0LmFwcGx5KHkucG9wKCksIG4pIHx8ICFZKGkpIHx8IGMgJiYgZyhpW21dKSAmJiAhdihpKSAmJiAoKHMgPSBpW2NdKSAmJiAoaVtjXSA9IG51bGwpLCB3LmV2ZW50LnRyaWdnZXJlZCA9IG0sIHQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSAmJiBoLmFkZEV2ZW50TGlzdGVuZXIobSwgY3QpLCBpW21dKCksIHQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSAmJiBoLnJlbW92ZUV2ZW50TGlzdGVuZXIobSwgY3QpLCB3LmV2ZW50LnRyaWdnZXJlZCA9IHZvaWQgMCwgcyAmJiAoaVtjXSA9IHMpKSwgdC5yZXN1bHQgfSB9LCBzaW11bGF0ZTogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIgPSB3LmV4dGVuZChuZXcgdy5FdmVudCwgbiwgeyB0eXBlOiBlLCBpc1NpbXVsYXRlZDogITAgfSk7IHcuZXZlbnQudHJpZ2dlcihyLCBudWxsLCB0KSB9IH0pLCB3LmZuLmV4dGVuZCh7IHRyaWdnZXI6IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24gKCkgeyB3LmV2ZW50LnRyaWdnZXIoZSwgdCwgdGhpcykgfSkgfSwgdHJpZ2dlckhhbmRsZXI6IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuID0gdGhpc1swXTsgaWYgKG4pIHJldHVybiB3LmV2ZW50LnRyaWdnZXIoZSwgdCwgbiwgITApIH0gfSksIGguZm9jdXNpbiB8fCB3LmVhY2goeyBmb2N1czogImZvY3VzaW4iLCBibHVyOiAiZm9jdXNvdXQiIH0sIGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuID0gZnVuY3Rpb24gKGUpIHsgdy5ldmVudC5zaW11bGF0ZSh0LCBlLnRhcmdldCwgdy5ldmVudC5maXgoZSkpIH07IHcuZXZlbnQuc3BlY2lhbFt0XSA9IHsgc2V0dXA6IGZ1bmN0aW9uICgpIHsgdmFyIHIgPSB0aGlzLm93bmVyRG9jdW1lbnQgfHwgdGhpcywgaSA9IEsuYWNjZXNzKHIsIHQpOyBpIHx8IHIuYWRkRXZlbnRMaXN0ZW5lcihlLCBuLCAhMCksIEsuYWNjZXNzKHIsIHQsIChpIHx8IDApICsgMSkgfSwgdGVhcmRvd246IGZ1bmN0aW9uICgpIHsgdmFyIHIgPSB0aGlzLm93bmVyRG9jdW1lbnQgfHwgdGhpcywgaSA9IEsuYWNjZXNzKHIsIHQpIC0gMTsgaSA/IEsuYWNjZXNzKHIsIHQsIGkpIDogKHIucmVtb3ZlRXZlbnRMaXN0ZW5lcihlLCBuLCAhMCksIEsucmVtb3ZlKHIsIHQpKSB9IH0gfSk7IHZhciBmdCA9IC9cW1xdJC8sIGR0ID0gL1xyP1xuL2csIHB0ID0gL14oPzpzdWJtaXR8YnV0dG9ufGltYWdlfHJlc2V0fGZpbGUpJC9pLCBodCA9IC9eKD86aW5wdXR8c2VsZWN0fHRleHRhcmVhfGtleWdlbikvaTsgZnVuY3Rpb24gZ3QoZSwgdCwgbiwgcikgeyB2YXIgaTsgaWYgKEFycmF5LmlzQXJyYXkodCkpIHcuZWFjaCh0LCBmdW5jdGlvbiAodCwgaSkgeyBuIHx8IGZ0LnRlc3QoZSkgPyByKGUsIGkpIDogZ3QoZSArICJbIiArICgib2JqZWN0IiA9PSB0eXBlb2YgaSAmJiBudWxsICE9IGkgPyB0IDogIiIpICsgIl0iLCBpLCBuLCByKSB9KTsgZWxzZSBpZiAobiB8fCAib2JqZWN0IiAhPT0gYih0KSkgcihlLCB0KTsgZWxzZSBmb3IgKGkgaW4gdCkgZ3QoZSArICJbIiArIGkgKyAiXSIsIHRbaV0sIG4sIHIpIH0gdy5wYXJhbSA9IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCByID0gW10sIGkgPSBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IGcodCkgPyB0KCkgOiB0OyByW3IubGVuZ3RoXSA9IGVuY29kZVVSSUNvbXBvbmVudChlKSArICI9IiArIGVuY29kZVVSSUNvbXBvbmVudChudWxsID09IG4gPyAiIiA6IG4pIH07IGlmIChBcnJheS5pc0FycmF5KGUpIHx8IGUuanF1ZXJ5ICYmICF3LmlzUGxhaW5PYmplY3QoZSkpIHcuZWFjaChlLCBmdW5jdGlvbiAoKSB7IGkodGhpcy5uYW1lLCB0aGlzLnZhbHVlKSB9KTsgZWxzZSBmb3IgKG4gaW4gZSkgZ3QobiwgZVtuXSwgdCwgaSk7IHJldHVybiByLmpvaW4oIiYiKSB9LCB3LmZuLmV4dGVuZCh7IHNlcmlhbGl6ZTogZnVuY3Rpb24gKCkgeyByZXR1cm4gdy5wYXJhbSh0aGlzLnNlcmlhbGl6ZUFycmF5KCkpIH0sIHNlcmlhbGl6ZUFycmF5OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLm1hcChmdW5jdGlvbiAoKSB7IHZhciBlID0gdy5wcm9wKHRoaXMsICJlbGVtZW50cyIpOyByZXR1cm4gZSA/IHcubWFrZUFycmF5KGUpIDogdGhpcyB9KS5maWx0ZXIoZnVuY3Rpb24gKCkgeyB2YXIgZSA9IHRoaXMudHlwZTsgcmV0dXJuIHRoaXMubmFtZSAmJiAhdyh0aGlzKS5pcygiOmRpc2FibGVkIikgJiYgaHQudGVzdCh0aGlzLm5vZGVOYW1lKSAmJiAhcHQudGVzdChlKSAmJiAodGhpcy5jaGVja2VkIHx8ICFkZS50ZXN0KGUpKSB9KS5tYXAoZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4gPSB3KHRoaXMpLnZhbCgpOyByZXR1cm4gbnVsbCA9PSBuID8gbnVsbCA6IEFycmF5LmlzQXJyYXkobikgPyB3Lm1hcChuLCBmdW5jdGlvbiAoZSkgeyByZXR1cm4geyBuYW1lOiB0Lm5hbWUsIHZhbHVlOiBlLnJlcGxhY2UoZHQsICJcclxuIikgfSB9KSA6IHsgbmFtZTogdC5uYW1lLCB2YWx1ZTogbi5yZXBsYWNlKGR0LCAiXHJcbiIpIH0gfSkuZ2V0KCkgfSB9KSwgdy5mbi5leHRlbmQoeyB3cmFwQWxsOiBmdW5jdGlvbiAoZSkgeyB2YXIgdDsgcmV0dXJuIHRoaXNbMF0gJiYgKGcoZSkgJiYgKGUgPSBlLmNhbGwodGhpc1swXSkpLCB0ID0gdyhlLCB0aGlzWzBdLm93bmVyRG9jdW1lbnQpLmVxKDApLmNsb25lKCEwKSwgdGhpc1swXS5wYXJlbnROb2RlICYmIHQuaW5zZXJ0QmVmb3JlKHRoaXNbMF0pLCB0Lm1hcChmdW5jdGlvbiAoKSB7IHZhciBlID0gdGhpczsgd2hpbGUgKGUuZmlyc3RFbGVtZW50Q2hpbGQpIGUgPSBlLmZpcnN0RWxlbWVudENoaWxkOyByZXR1cm4gZSB9KS5hcHBlbmQodGhpcykpLCB0aGlzIH0sIHdyYXBJbm5lcjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGcoZSkgPyB0aGlzLmVhY2goZnVuY3Rpb24gKHQpIHsgdyh0aGlzKS53cmFwSW5uZXIoZS5jYWxsKHRoaXMsIHQpKSB9KSA6IHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7IHZhciB0ID0gdyh0aGlzKSwgbiA9IHQuY29udGVudHMoKTsgbi5sZW5ndGggPyBuLndyYXBBbGwoZSkgOiB0LmFwcGVuZChlKSB9KSB9LCB3cmFwOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGcoZSk7IHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24gKG4pIHsgdyh0aGlzKS53cmFwQWxsKHQgPyBlLmNhbGwodGhpcywgbikgOiBlKSB9KSB9LCB1bndyYXA6IGZ1bmN0aW9uIChlKSB7IHJldHVybiB0aGlzLnBhcmVudChlKS5ub3QoImJvZHkiKS5lYWNoKGZ1bmN0aW9uICgpIHsgdyh0aGlzKS5yZXBsYWNlV2l0aCh0aGlzLmNoaWxkTm9kZXMpIH0pLCB0aGlzIH0gfSksIHcuZXhwci5wc2V1ZG9zLmhpZGRlbiA9IGZ1bmN0aW9uIChlKSB7IHJldHVybiAhdy5leHByLnBzZXVkb3MudmlzaWJsZShlKSB9LCB3LmV4cHIucHNldWRvcy52aXNpYmxlID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuICEhKGUub2Zmc2V0V2lkdGggfHwgZS5vZmZzZXRIZWlnaHQgfHwgZS5nZXRDbGllbnRSZWN0cygpLmxlbmd0aCkgfSwgaC5jcmVhdGVIVE1MRG9jdW1lbnQgPSBmdW5jdGlvbiAoKSB7IHZhciBlID0gci5pbXBsZW1lbnRhdGlvbi5jcmVhdGVIVE1MRG9jdW1lbnQoIiIpLmJvZHk7IHJldHVybiBlLmlubmVySFRNTCA9ICI8Zm9ybT48L2Zvcm0+PGZvcm0+PC9mb3JtPiIsIDIgPT09IGUuY2hpbGROb2Rlcy5sZW5ndGggfSgpLCB3LnBhcnNlSFRNTCA9IGZ1bmN0aW9uIChlLCB0LCBuKSB7IGlmICgic3RyaW5nIiAhPSB0eXBlb2YgZSkgcmV0dXJuIFtdOyAiYm9vbGVhbiIgPT0gdHlwZW9mIHQgJiYgKG4gPSB0LCB0ID0gITEpOyB2YXIgaSwgbywgYTsgcmV0dXJuIHQgfHwgKGguY3JlYXRlSFRNTERvY3VtZW50ID8gKChpID0gKHQgPSByLmltcGxlbWVudGF0aW9uLmNyZWF0ZUhUTUxEb2N1bWVudCgiIikpLmNyZWF0ZUVsZW1lbnQoImJhc2UiKSkuaHJlZiA9IHIubG9jYXRpb24uaHJlZiwgdC5oZWFkLmFwcGVuZENoaWxkKGkpKSA6IHQgPSByKSwgbyA9IFMuZXhlYyhlKSwgYSA9ICFuICYmIFtdLCBvID8gW3QuY3JlYXRlRWxlbWVudChvWzFdKV0gOiAobyA9IGJlKFtlXSwgdCwgYSksIGEgJiYgYS5sZW5ndGggJiYgdyhhKS5yZW1vdmUoKSwgdy5tZXJnZShbXSwgby5jaGlsZE5vZGVzKSkgfSwgdy5vZmZzZXQgPSB7IHNldE9mZnNldDogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIsIGksIG8sIGEsIHUsIHMsIGwsIGMgPSB3LmNzcyhlLCAicG9zaXRpb24iKSwgZiA9IHcoZSksIGQgPSB7fTsgInN0YXRpYyIgPT09IGMgJiYgKGUuc3R5bGUucG9zaXRpb24gPSAicmVsYXRpdmUiKSwgdSA9IGYub2Zmc2V0KCksIG8gPSB3LmNzcyhlLCAidG9wIiksIHMgPSB3LmNzcyhlLCAibGVmdCIpLCAobCA9ICgiYWJzb2x1dGUiID09PSBjIHx8ICJmaXhlZCIgPT09IGMpICYmIChvICsgcykuaW5kZXhPZigiYXV0byIpID4gLTEpID8gKGEgPSAociA9IGYucG9zaXRpb24oKSkudG9wLCBpID0gci5sZWZ0KSA6IChhID0gcGFyc2VGbG9hdChvKSB8fCAwLCBpID0gcGFyc2VGbG9hdChzKSB8fCAwKSwgZyh0KSAmJiAodCA9IHQuY2FsbChlLCBuLCB3LmV4dGVuZCh7fSwgdSkpKSwgbnVsbCAhPSB0LnRvcCAmJiAoZC50b3AgPSB0LnRvcCAtIHUudG9wICsgYSksIG51bGwgIT0gdC5sZWZ0ICYmIChkLmxlZnQgPSB0LmxlZnQgLSB1LmxlZnQgKyBpKSwgInVzaW5nIiBpbiB0ID8gdC51c2luZy5jYWxsKGUsIGQpIDogZi5jc3MoZCkgfSB9LCB3LmZuLmV4dGVuZCh7IG9mZnNldDogZnVuY3Rpb24gKGUpIHsgaWYgKGFyZ3VtZW50cy5sZW5ndGgpIHJldHVybiB2b2lkIDAgPT09IGUgPyB0aGlzIDogdGhpcy5lYWNoKGZ1bmN0aW9uICh0KSB7IHcub2Zmc2V0LnNldE9mZnNldCh0aGlzLCBlLCB0KSB9KTsgdmFyIHQsIG4sIHIgPSB0aGlzWzBdOyBpZiAocikgcmV0dXJuIHIuZ2V0Q2xpZW50UmVjdHMoKS5sZW5ndGggPyAodCA9IHIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksIG4gPSByLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcsIHsgdG9wOiB0LnRvcCArIG4ucGFnZVlPZmZzZXQsIGxlZnQ6IHQubGVmdCArIG4ucGFnZVhPZmZzZXQgfSkgOiB7IHRvcDogMCwgbGVmdDogMCB9IH0sIHBvc2l0aW9uOiBmdW5jdGlvbiAoKSB7IGlmICh0aGlzWzBdKSB7IHZhciBlLCB0LCBuLCByID0gdGhpc1swXSwgaSA9IHsgdG9wOiAwLCBsZWZ0OiAwIH07IGlmICgiZml4ZWQiID09PSB3LmNzcyhyLCAicG9zaXRpb24iKSkgdCA9IHIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7IGVsc2UgeyB0ID0gdGhpcy5vZmZzZXQoKSwgbiA9IHIub3duZXJEb2N1bWVudCwgZSA9IHIub2Zmc2V0UGFyZW50IHx8IG4uZG9jdW1lbnRFbGVtZW50OyB3aGlsZSAoZSAmJiAoZSA9PT0gbi5ib2R5IHx8IGUgPT09IG4uZG9jdW1lbnRFbGVtZW50KSAmJiAic3RhdGljIiA9PT0gdy5jc3MoZSwgInBvc2l0aW9uIikpIGUgPSBlLnBhcmVudE5vZGU7IGUgJiYgZSAhPT0gciAmJiAxID09PSBlLm5vZGVUeXBlICYmICgoaSA9IHcoZSkub2Zmc2V0KCkpLnRvcCArPSB3LmNzcyhlLCAiYm9yZGVyVG9wV2lkdGgiLCAhMCksIGkubGVmdCArPSB3LmNzcyhlLCAiYm9yZGVyTGVmdFdpZHRoIiwgITApKSB9IHJldHVybiB7IHRvcDogdC50b3AgLSBpLnRvcCAtIHcuY3NzKHIsICJtYXJnaW5Ub3AiLCAhMCksIGxlZnQ6IHQubGVmdCAtIGkubGVmdCAtIHcuY3NzKHIsICJtYXJnaW5MZWZ0IiwgITApIH0gfSB9LCBvZmZzZXRQYXJlbnQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMubWFwKGZ1bmN0aW9uICgpIHsgdmFyIGUgPSB0aGlzLm9mZnNldFBhcmVudDsgd2hpbGUgKGUgJiYgInN0YXRpYyIgPT09IHcuY3NzKGUsICJwb3NpdGlvbiIpKSBlID0gZS5vZmZzZXRQYXJlbnQ7IHJldHVybiBlIHx8IHhlIH0pIH0gfSksIHcuZWFjaCh7IHNjcm9sbExlZnQ6ICJwYWdlWE9mZnNldCIsIHNjcm9sbFRvcDogInBhZ2VZT2Zmc2V0IiB9LCBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9ICJwYWdlWU9mZnNldCIgPT09IHQ7IHcuZm5bZV0gPSBmdW5jdGlvbiAocikgeyByZXR1cm4gXyh0aGlzLCBmdW5jdGlvbiAoZSwgciwgaSkgeyB2YXIgbzsgaWYgKHYoZSkgPyBvID0gZSA6IDkgPT09IGUubm9kZVR5cGUgJiYgKG8gPSBlLmRlZmF1bHRWaWV3KSwgdm9pZCAwID09PSBpKSByZXR1cm4gbyA/IG9bdF0gOiBlW3JdOyBvID8gby5zY3JvbGxUbyhuID8gby5wYWdlWE9mZnNldCA6IGksIG4gPyBpIDogby5wYWdlWU9mZnNldCkgOiBlW3JdID0gaSB9LCBlLCByLCBhcmd1bWVudHMubGVuZ3RoKSB9IH0pLCB3LmVhY2goWyJ0b3AiLCAibGVmdCJdLCBmdW5jdGlvbiAoZSwgdCkgeyB3LmNzc0hvb2tzW3RdID0gemUoaC5waXhlbFBvc2l0aW9uLCBmdW5jdGlvbiAoZSwgbikgeyBpZiAobikgcmV0dXJuIG4gPSBGZShlLCB0KSwgTWUudGVzdChuKSA/IHcoZSkucG9zaXRpb24oKVt0XSArICJweCIgOiBuIH0pIH0pLCB3LmVhY2goeyBIZWlnaHQ6ICJoZWlnaHQiLCBXaWR0aDogIndpZHRoIiB9LCBmdW5jdGlvbiAoZSwgdCkgeyB3LmVhY2goeyBwYWRkaW5nOiAiaW5uZXIiICsgZSwgY29udGVudDogdCwgIiI6ICJvdXRlciIgKyBlIH0sIGZ1bmN0aW9uIChuLCByKSB7IHcuZm5bcl0gPSBmdW5jdGlvbiAoaSwgbykgeyB2YXIgYSA9IGFyZ3VtZW50cy5sZW5ndGggJiYgKG4gfHwgImJvb2xlYW4iICE9IHR5cGVvZiBpKSwgdSA9IG4gfHwgKCEwID09PSBpIHx8ICEwID09PSBvID8gIm1hcmdpbiIgOiAiYm9yZGVyIik7IHJldHVybiBfKHRoaXMsIGZ1bmN0aW9uICh0LCBuLCBpKSB7IHZhciBvOyByZXR1cm4gdih0KSA/IDAgPT09IHIuaW5kZXhPZigib3V0ZXIiKSA/IHRbImlubmVyIiArIGVdIDogdC5kb2N1bWVudC5kb2N1bWVudEVsZW1lbnRbImNsaWVudCIgKyBlXSA6IDkgPT09IHQubm9kZVR5cGUgPyAobyA9IHQuZG9jdW1lbnRFbGVtZW50LCBNYXRoLm1heCh0LmJvZHlbInNjcm9sbCIgKyBlXSwgb1sic2Nyb2xsIiArIGVdLCB0LmJvZHlbIm9mZnNldCIgKyBlXSwgb1sib2Zmc2V0IiArIGVdLCBvWyJjbGllbnQiICsgZV0pKSA6IHZvaWQgMCA9PT0gaSA/IHcuY3NzKHQsIG4sIHUpIDogdy5zdHlsZSh0LCBuLCBpLCB1KSB9LCB0LCBhID8gaSA6IHZvaWQgMCwgYSkgfSB9KSB9KSwgdy5lYWNoKCJibHVyIGZvY3VzIGZvY3VzaW4gZm9jdXNvdXQgcmVzaXplIHNjcm9sbCBjbGljayBkYmxjbGljayBtb3VzZWRvd24gbW91c2V1cCBtb3VzZW1vdmUgbW91c2VvdmVyIG1vdXNlb3V0IG1vdXNlZW50ZXIgbW91c2VsZWF2ZSBjaGFuZ2Ugc2VsZWN0IHN1Ym1pdCBrZXlkb3duIGtleXByZXNzIGtleXVwIGNvbnRleHRtZW51Ii5zcGxpdCgiICIpLCBmdW5jdGlvbiAoZSwgdCkgeyB3LmZuW3RdID0gZnVuY3Rpb24gKGUsIG4pIHsgcmV0dXJuIGFyZ3VtZW50cy5sZW5ndGggPiAwID8gdGhpcy5vbih0LCBudWxsLCBlLCBuKSA6IHRoaXMudHJpZ2dlcih0KSB9IH0pLCB3LmZuLmV4dGVuZCh7IGhvdmVyOiBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gdGhpcy5tb3VzZWVudGVyKGUpLm1vdXNlbGVhdmUodCB8fCBlKSB9IH0pLCB3LmZuLmV4dGVuZCh7IGJpbmQ6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiB0aGlzLm9uKGUsIG51bGwsIHQsIG4pIH0sIHVuYmluZDogZnVuY3Rpb24gKGUsIHQpIHsgcmV0dXJuIHRoaXMub2ZmKGUsIG51bGwsIHQpIH0sIGRlbGVnYXRlOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyByZXR1cm4gdGhpcy5vbih0LCBlLCBuLCByKSB9LCB1bmRlbGVnYXRlOiBmdW5jdGlvbiAoZSwgdCwgbikgeyByZXR1cm4gMSA9PT0gYXJndW1lbnRzLmxlbmd0aCA/IHRoaXMub2ZmKGUsICIqKiIpIDogdGhpcy5vZmYodCwgZSB8fCAiKioiLCBuKSB9IH0pLCB3LnByb3h5ID0gZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIsIGk7IGlmICgic3RyaW5nIiA9PSB0eXBlb2YgdCAmJiAobiA9IGVbdF0sIHQgPSBlLCBlID0gbiksIGcoZSkpIHJldHVybiByID0gby5jYWxsKGFyZ3VtZW50cywgMiksIGkgPSBmdW5jdGlvbiAoKSB7IHJldHVybiBlLmFwcGx5KHQgfHwgdGhpcywgci5jb25jYXQoby5jYWxsKGFyZ3VtZW50cykpKSB9LCBpLmd1aWQgPSBlLmd1aWQgPSBlLmd1aWQgfHwgdy5ndWlkKysgLCBpIH0sIHcuaG9sZFJlYWR5ID0gZnVuY3Rpb24gKGUpIHsgZSA/IHcucmVhZHlXYWl0KysgOiB3LnJlYWR5KCEwKSB9LCB3LmlzQXJyYXkgPSBBcnJheS5pc0FycmF5LCB3LnBhcnNlSlNPTiA9IEpTT04ucGFyc2UsIHcubm9kZU5hbWUgPSBELCB3LmlzRnVuY3Rpb24gPSBnLCB3LmlzV2luZG93ID0gdiwgdy5jYW1lbENhc2UgPSBRLCB3LnR5cGUgPSBiLCB3Lm5vdyA9IERhdGUubm93LCB3LmlzTnVtZXJpYyA9IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gdy50eXBlKGUpOyByZXR1cm4gKCJudW1iZXIiID09PSB0IHx8ICJzdHJpbmciID09PSB0KSAmJiAhaXNOYU4oZSAtIHBhcnNlRmxvYXQoZSkpIH0sICJmdW5jdGlvbiIgPT0gdHlwZW9mIGRlZmluZSAmJiBkZWZpbmUuYW1kICYmIGRlZmluZSgianF1ZXJ5IiwgW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHcgfSk7IHZhciB2dCA9IGUualF1ZXJ5LCB5dCA9IGUuJDsgcmV0dXJuIHcubm9Db25mbGljdCA9IGZ1bmN0aW9uICh0KSB7IHJldHVybiBlLiQgPT09IHcgJiYgKGUuJCA9IHl0KSwgdCAmJiBlLmpRdWVyeSA9PT0gdyAmJiAoZS5qUXVlcnkgPSB2dCksIHcgfSwgdCB8fCAoZS5qUXVlcnkgPSBlLiQgPSB3KSwgdyB9KTs=\"") + packr.PackJSONBytes("./assets/default", "wails.js", "\"Ly8gV2FpbHMgcnVudGltZSBKUwoKKGZ1bmN0aW9uICgpIHsKCXdpbmRvdy53YWlscyA9IHdpbmRvdy53YWlscyB8fCB7CgkJJDoge30KCX07CgoJLyoqKioqKioqKioqKioqKioqKiBVdGlsaXR5IEZ1bmN0aW9ucyAqKioqKioqKioqKioqKioqKioqKioqKiovCgoJLy8gLS0tLS0tLS0tLS0tLS0gUmFuZG9tIC0tLS0tLS0tLS0tLS0tCgkvLyBBd2Vzb21lUmFuZG9tCglmdW5jdGlvbiBjcnlwdG9SYW5kb20oKSB7CgkJdmFyIGFycmF5ID0gbmV3IFVpbnQzMkFycmF5KDEpOwoJCXJldHVybiB3aW5kb3cuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhhcnJheSlbMF07Cgl9CgoJLy8gTE9MUmFuZG9tCglmdW5jdGlvbiBiYXNpY1JhbmRvbSgpIHsKCQlyZXR1cm4gTWF0aC5yYW5kb20oKSAqIDkwMDcxOTkyNTQ3NDA5OTE7Cgl9CgoJLy8gUGljayBvbmUgYmFzZWQgb24gYnJvd3NlciBjYXBhYmlsaXR5Cgl2YXIgcmFuZG9tRnVuYzsKCWlmICh3aW5kb3cuY3J5cHRvKSB7CgkJcmFuZG9tRnVuYyA9IGNyeXB0b1JhbmRvbTsKCX0gZWxzZSB7CgkJcmFuZG9tRnVuYyA9IGJhc2ljUmFuZG9tOwoJfQoKCS8vIC0tLS0tLS0tLS0tLS0tIElkZW50aWZpZXJzIC0tLS0tLS0tLS0tLS0tLQoKCWZ1bmN0aW9uIGlzVmFsaWRJZGVudGlmaWVyKG5hbWUpIHsKCQkvLyBEb24ndCB4c3MgeW91cnNlbGYgOi0pCgkJdHJ5IHsKCQkJbmV3IEZ1bmN0aW9uKCJ2YXIgIiArIG5hbWUpOwoJCQlyZXR1cm4gdHJ1ZQoJCX0gY2F0Y2ggKGUpIHsKCQkJcmV0dXJuIGZhbHNlCgkJfQoJfQoKCS8vIC0tLS0tLS0tLS0tLS0tIEpTIC0tLS0tLS0tLS0tLS0tLS0KCWZ1bmN0aW9uIGFkZFNjcmlwdChqcywgY2FsbGJhY2tJRCkgewoJCWNvbnNvbGUubG9nKCJBZGRpbmcgc2NyaXB0OiAiICsganMpCgkJdmFyIHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInNjcmlwdCIpOwoJCXNjcmlwdC50ZXh0ID0ganM7CgkJZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChzY3JpcHQpOwoJCWNvbnNvbGUubG9nKCJDYWxsaW5nIGJhY2sgd2l0aDoiICsgY2FsbGJhY2tJRCk7CgkJd2luZG93LndhaWxzLmV2ZW50cy5lbWl0KGNhbGxiYWNrSUQpOwoJfQoKCS8vIC0tLS0tLS0tLS0tLS0tIEhUTUwgLS0tLS0tLS0tLS0tLS0KCWZ1bmN0aW9uIHNldERvY3VtZW50KGh0bWwpIHsKCQlkb2N1bWVudC5vcGVuKCk7CgkJZG9jdW1lbnQud3JpdGUoaHRtbCk7CgkJZG9jdW1lbnQuY2xvc2UoKTsKCX0KCgkvLyAtLS0tLS0tLS0tLS0tLSBDU1MgLS0tLS0tLS0tLS0tLS0tCgkvLyBBZGFwdGVkIGZyb20gd2VidmlldyAtIHRoYW5rcyB6c2VyZ2UhCglmdW5jdGlvbiBpbmplY3RDU1MoY3NzKSB7CgkJdmFyIGVsZW0gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzdHlsZScpOwoJCWVsZW0uc2V0QXR0cmlidXRlKCd0eXBlJywgJ3RleHQvY3NzJyk7CgkJaWYgKGVsZW0uc3R5bGVTaGVldCkgewoJCQllbGVtLnN0eWxlU2hlZXQuY3NzVGV4dCA9IGNzczsKCQl9IGVsc2UgewoJCQllbGVtLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGNzcykpOwoJCX0KCQl2YXIgaGVhZCA9IGRvY3VtZW50LmhlYWQgfHwgZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2hlYWQnKVswXTsKCQloZWFkLmFwcGVuZENoaWxkKGVsZW0pCgl9CgoJLyoqKioqKioqKioqKioqKioqKioqKioqKiogQmluZGluZ3MgKioqKioqKioqKioqKioqKioqKioqKioqKi8KCgl2YXIgYmluZGluZ3NCYXNlUGF0aCA9IHdpbmRvdy53YWlscy4kOwoKCS8vIENyZWF0ZXMgdGhlIHBhdGggZ2l2ZW4gaW4gdGhlIGJpbmRpbmdzIHBhdGgKCWZ1bmN0aW9uIGFkZEJpbmRpbmdQYXRoKHBhdGhTZWN0aW9ucykgewoJCS8vIFN0YXJ0IGF0IHRoZSBiYXNlIHBhdGgKCQl2YXIgY3VycmVudFBhdGggPSBiaW5kaW5nc0Jhc2VQYXRoCgkJLy8gZm9yIGVhY2ggc2VjdGlvbiBvZiB0aGUgZ2l2ZW4gcGF0aAoJCWZvciAodmFyIHNlY3Rpb24gb2YgcGF0aFNlY3Rpb25zKSB7CgoJCQkvLyBJcyBzZWN0aW9uIGEgdmFsaWQgamF2YXNjcmlwdCBpZGVudGlmaWVyPwoJCQlpZiAoIWlzVmFsaWRJZGVudGlmaWVyKHNlY3Rpb24pKSB7CgkJCQl2YXIgZXJyTWVzc2FnZSA9IHNlY3Rpb24gKyAiIGlzIG5vdCBhIHZhbGlkIGphdmFzY3JpcHQgaWRlbnRpZmllci4iCgkJCQl2YXIgZXJyID0gbmV3IEVycm9yKGVyck1lc3NhZ2UpCgkJCQlyZXR1cm4gW251bGwsIGVycl0KCQkJfQoKCQkJLy8gQWRkIGlmIGRvZXNuJ3QgZXhpc3QKCQkJaWYgKCFjdXJyZW50UGF0aFtzZWN0aW9uXSkgewoJCQkJY3VycmVudFBhdGhbc2VjdGlvbl0gPSB7fQoJCQl9CgkJCS8vIHVwZGF0ZSBjdXJyZW50IHBhdGggdG8gbmV3IHBhdGgKCQkJY3VycmVudFBhdGggPSBjdXJyZW50UGF0aFtzZWN0aW9uXQoJCX0KCQlyZXR1cm4gW2N1cnJlbnRQYXRoLCBudWxsXQoJfQoKCWZ1bmN0aW9uIG5ld0JpbmRpbmcoYmluZGluZ05hbWUpIHsKCgkJLy8gR2V0IGFsbCB0aGUgc2VjdGlvbnMgb2YgdGhlIGJpbmRpbmcKCQl2YXIgYmluZGluZ1NlY3Rpb25zID0gYmluZGluZ05hbWUuc3BsaXQoJy4nKTsKCgkJLy8gR2V0IHRoZSBhY3R1YWwgZnVuY3Rpb24vbWV0aG9kIGNhbGwgbmFtZQoJCXZhciBjYWxsTmFtZSA9IGJpbmRpbmdTZWN0aW9ucy5wb3AoKTsKCgkJLy8gQWRkIHBhdGggdG8gYmluZGluZwoJCVtwYXRoVG9CaW5kaW5nLCBlcnJdID0gYWRkQmluZGluZ1BhdGgoYmluZGluZ1NlY3Rpb25zKQoKCQlpZiAoZXJyICE9IG51bGwpIHsKCQkJLy8gV2UgbmVlZCB0byByZXR1cm4gYW4gZXJyb3IKCQkJLy8gd2luZG93LndhaWxzLmxvZy5FcnJvcigiIikKCQkJcmV0dXJuCgkJfQoKCQkvLyBBZGQgYmluZGluZyBjYWxsCgkJcGF0aFRvQmluZGluZ1tjYWxsTmFtZV0gPSBmdW5jdGlvbiAoKSB7CgoJCQkvLyBObyB0aW1lb3V0IGJ5IGRlZmF1bHQKCQkJdmFyIHRpbWVvdXQgPSAwOwoKCQkJLy8gQWN0dWFsIGZ1bmN0aW9uCgkJCWZ1bmN0aW9uIGR5bmFtaWMoKSB7CgkJCQl2YXIgYXJncyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKQoJCQkJcmV0dXJuIGNhbGwoYmluZGluZ05hbWUsIGFyZ3MsIHRpbWVvdXQpOwoJCQl9CgoJCQkvLyBBbGxvdyBzZXR0aW5nIHRpbWVvdXQgdG8gZnVuY3Rpb24KCQkJZHluYW1pYy5zZXRUaW1lb3V0ID0gZnVuY3Rpb24gKG5ld1RpbWVvdXQpIHsKCQkJCXRpbWVvdXQgPSBuZXdUaW1lb3V0OwoJCQl9CgoJCQkvLyBBbGxvdyBnZXR0aW5nIHRpbWVvdXQgdG8gZnVuY3Rpb24KCQkJZHluYW1pYy5nZXRUaW1lb3V0ID0gZnVuY3Rpb24gKCkgewoJCQkJcmV0dXJuIHRpbWVvdXQ7CgkJCX0KCgkJCXJldHVybiBkeW5hbWljOwoJCX0oKTsKCX0KCgkvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKCS8qKioqKioqKioqKioqKioqKioqKioqKioqKiogQ2FsbHMgKioqKioqKioqKioqKioqKioqKioqKioqKiovCgoJdmFyIGNhbGxiYWNrcyA9IHt9OwoKCS8vIENhbGwgc2VuZHMgYSBtZXNzYWdlIHRvIHRoZSBiYWNrZW5kIHRvIGNhbGwgdGhlIGJpbmRpbmcgd2l0aCB0aGUKCS8vIGdpdmVuIGRhdGEuIEEgcHJvbWlzZSBpcyByZXR1cm5lZCBhbmQgd2lsbCBiZSBjb21wbGV0ZWQgd2hlbiB0aGUKCS8vIGJhY2tlbmQgcmVzcG9uZHMuIFRoaXMgd2lsbCBiZSByZXNvbHZlZCB3aGVuIHRoZSBjYWxsIHdhcyBzdWNjZXNzZnVsCgkvLyBvciByZWplY3RlZCBpZiBhbiBlcnJvciBpcyBwYXNzZWQgYmFjay4KCS8vIFRoZXJlIGlzIGEgdGltZW91dCBtZWNoYW5pc20uIElmIHRoZSBjYWxsIGRvZXNuJ3QgcmVzcG9uZCBpbiB0aGUgZ2l2ZW4KCS8vIHRpbWUgKGluIG1pbGxpc2Vjb25kcykgdGhlbiB0aGUgcHJvbWlzZSBpcyByZWplY3RlZC4KCglmdW5jdGlvbiBjYWxsKGJpbmRpbmdOYW1lLCBkYXRhLCB0aW1lb3V0KSB7CgoJCS8vIFRpbWVvdXQgaW5maW5pdGUgYnkgZGVmYXVsdAoJCWlmICh0aW1lb3V0ID09IG51bGwgfHwgdGltZW91dCA9PSB1bmRlZmluZWQpIHsKCQkJdGltZW91dCA9IDA7CgkJfQoKCQkvLyBDcmVhdGUgYSBwcm9taXNlCgkJcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHsKCgkJCS8vIENyZWF0ZSBhIHVuaXF1ZSBjYWxsYmFja0lECgkJCXZhciBjYWxsYmFja0lEOwoJCQlkbyB7CgkJCQljYWxsYmFja0lEID0gYmluZGluZ05hbWUgKyAiLSIgKyByYW5kb21GdW5jKCk7CgkJCX0gd2hpbGUgKGNhbGxiYWNrc1tjYWxsYmFja0lEXSkKCgkJCS8vIFNldCB0aW1lb3V0CgkJCWlmICh0aW1lb3V0ID4gMCkgewoJCQkJdmFyIHRpbWVvdXRIYW5kbGUgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHsKCQkJCQlyZWplY3QoRXJyb3IoIkNhbGwgdG8gIiArIGJpbmRpbmdOYW1lICsgIiB0aW1lZCBvdXQuIFJlcXVlc3QgSUQ6ICIgKyBjYWxsYmFja0lEKSkKCQkJCX0sIHRpbWVvdXQpOwoJCQl9CgoJCQkvLyBTdG9yZSBjYWxsYmFjawoJCQljYWxsYmFja3NbY2FsbGJhY2tJRF0gPSB7CgkJCQl0aW1lb3V0SGFuZGxlOiB0aW1lb3V0SGFuZGxlLAoJCQkJcmVqZWN0OiByZWplY3QsCgkJCQlyZXNvbHZlOiByZXNvbHZlCgkJCX0KCQkJdHJ5IHsKCQkJCXZhciBwYXlsb2FkZGF0YSA9IEpTT04uc3RyaW5naWZ5KGRhdGEpCgkJCQkvLyBDcmVhdGUgdGhlIG1lc3NhZ2UKCQkJCW1lc3NhZ2UgPSB7CgkJCQkJdHlwZTogImNhbGwiLAoJCQkJCWNhbGxiYWNraWQ6IGNhbGxiYWNrSUQsCgkJCQkJcGF5bG9hZDogewoJCQkJCQliaW5kaW5nTmFtZTogYmluZGluZ05hbWUsCgkJCQkJCWRhdGE6IHBheWxvYWRkYXRhLAoJCQkJCX0KCQkJCX0KCgkJCQkvLyBNYWtlIHRoZSBjYWxsCgkJCQl2YXIgcGF5bG9hZCA9IEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpCgkJCQlleHRlcm5hbC5pbnZva2UocGF5bG9hZCk7CgkJCX0gY2F0Y2ggKGUpIHsKCQkJCWNvbnNvbGUuZXJyb3IoZSkKCQkJfQoJCX0pCgl9CgoKCS8vIENhbGxlZCBieSB0aGUgYmFja2VuZCB0byByZXR1cm4gZGF0YSB0byBhIHByZXZpb3VzbHkgY2FsbGVkCgkvLyBiaW5kaW5nIGludm9jYXRpb24KCWZ1bmN0aW9uIGNhbGxiYWNrKGluY29taW5nTWVzc2FnZSkgewoJCS8vIHdhaWxzLmxvZy5kZWJ1ZygiY2FsbGJhY2sgY2FsbGVkIHdpdGg6ICIgKyBpbmNvbWluZ01lc3NhZ2UpCgkJLy8gUGFyc2UgdGhlIG1lc3NhZ2UKCQl2YXIgbWVzc2FnZQoJCS8vIHdhaWxzLmxvZy5kZWJ1ZyhpbmNvbWluZ01lc3NhZ2UpCgkJdHJ5IHsKCQkJbWVzc2FnZSA9IEpTT04ucGFyc2UoaW5jb21pbmdNZXNzYWdlKQoJCX0gY2F0Y2ggKGUpIHsKCQkJd2FpbHMubG9nLmRlYnVnKCJJbnZhbGlkIEpTT04gcGFzc2VkIHRvIGNhbGxiYWNrOiAiICsgZS5tZXNzYWdlKQoJCQl3YWlscy5sb2cuZGVidWcoIk1lc3NhZ2U6ICIgKyBpbmNvbWluZ01lc3NhZ2UpCgkJCXJldHVybgoJCX0KCQljYWxsYmFja0lEID0gbWVzc2FnZS5jYWxsYmFja2lkCgkJY2FsbGJhY2tEYXRhID0gY2FsbGJhY2tzW2NhbGxiYWNrSURdCgkJaWYgKCFjYWxsYmFja0RhdGEpIHsKCQkJY29uc29sZS5lcnJvcigiQ2FsbGJhY2sgJyIgKyBjYWxsYmFja0lEICsgIicgbm90IHJlZ2lzdGVkISEhIikKCQkJcmV0dXJuCgkJfQoJCWNsZWFyVGltZW91dChjYWxsYmFja0RhdGEudGltZW91dEhhbmRsZSkKCQlkZWxldGUgY2FsbGJhY2tzW2NhbGxiYWNrSURdCgkJaWYgKG1lc3NhZ2UuZXJyb3IpIHsKCQkJcmV0dXJuIGNhbGxiYWNrRGF0YS5yZWplY3QobWVzc2FnZS5lcnJvcikKCQl9CgkJcmV0dXJuIGNhbGxiYWNrRGF0YS5yZXNvbHZlKG1lc3NhZ2UuZGF0YSkKCX0KCgkvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKCgkvKioqKioqKioqKioqKioqKioqKioqKioqKiogRXZlbnRzICoqKioqKioqKioqKioqKioqKioqKioqKioqLwoKCXZhciBldmVudExpc3RlbmVycyA9IHt9OwoKCS8vIFJlZ2lzdGVycyBldmVudCBsaXN0ZW5lcnMKCWZ1bmN0aW9uIG9uKGV2ZW50TmFtZSwgY2FsbGJhY2spIHsKCQlldmVudExpc3RlbmVyc1tldmVudE5hbWVdID0gZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSB8fCBbXTsKCQlldmVudExpc3RlbmVyc1tldmVudE5hbWVdLnB1c2goY2FsbGJhY2spOwoJfQoKCS8vIG5vdGlmeSBpbmZvcm1zIGZyb250ZW5kIGxpc3RlbmVycyB0aGF0IGFuIGV2ZW50IHdhcyBlbWl0dGVkIHdpdGggdGhlIGdpdmVuIGRhdGEKCWZ1bmN0aW9uIG5vdGlmeShldmVudE5hbWUsIGRhdGEpIHsKCQlpZiAoZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSkgewoJCQlldmVudExpc3RlbmVyc1tldmVudE5hbWVdLmZvckVhY2goZWxlbWVudCA9PiB7CgkJCQl2YXIgcGFyc2VkRGF0YSA9IFtdCgkJCQkvLyBQYXJzZSBkYXRhIGlmIHdlIGhhdmUgaXQKCQkJCWlmIChkYXRhKSB7CgkJCQkJdHJ5IHsKCQkJCQkJcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoZGF0YSk7CgkJCQkJfSBjYXRjaCAoZSkgewoJCQkJCQl3YWlscy5sb2cuZXJyb3IoIkludmFsaWQgSlNPTiBkYXRhIHNlbnQgdG8gbm90aWZ5LiBFdmVudCBuYW1lID0gIiArIGV2ZW50TmFtZSkKCQkJCQl9CgkJCQl9CgkJCQllbGVtZW50LmFwcGx5KG51bGwsIHBhcnNlZERhdGEpOwoJCQl9KTsKCQl9Cgl9CgoJLy8gZW1pdCBhbiBldmVudCB3aXRoIHRoZSBnaXZlbiBuYW1lIGFuZCBkYXRhCglmdW5jdGlvbiBlbWl0KGV2ZW50TmFtZSkgewoKCQkvLyBDYWxjdWxhdGUgdGhlIGRhdGEKCQl2YXIgZGF0YSA9IEpTT04uc3RyaW5naWZ5KFtdLnNsaWNlLmFwcGx5KGFyZ3VtZW50cykuc2xpY2UoMSkpOwoKCQkvLyBOb3RpZnkgYmFja2VuZAoJCW1lc3NhZ2UgPSB7CgkJCXR5cGU6ICJldmVudCIsCgkJCXBheWxvYWQ6IHsKCQkJCW5hbWU6IGV2ZW50TmFtZSwKCQkJCWRhdGE6IGRhdGEsCgkJCX0KCQl9CgkJZXh0ZXJuYWwuaW52b2tlKEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpKTsKCX0KCgkvLyBFdmVudHMgY2FsbHMKCXdpbmRvdy53YWlscy5ldmVudHMgPSB7IGVtaXQ6IGVtaXQsIG9uOiBvbiB9OwoKCS8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovCgoJLyoqKioqKioqKioqKioqKioqKioqKioqKiogTG9nZ2luZyAqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCgkvLyBTZW5kcyBhIGxvZyBtZXNzYWdlIHRvIHRoZSBiYWNrZW5kIHdpdGggdGhlIGdpdmVuCgkvLyBsZXZlbCArIG1lc3NhZ2UKCWZ1bmN0aW9uIHNlbmRMb2dNZXNzYWdlKGxldmVsLCBtZXNzYWdlKSB7CgoJCS8vIExvZyBNZXNzYWdlCgkJbWVzc2FnZSA9IHsKCQkJdHlwZTogImxvZyIsCgkJCXBheWxvYWQ6IHsKCQkJCWxldmVsOiBsZXZlbCwKCQkJCW1lc3NhZ2U6IG1lc3NhZ2UsCgkJCX0KCQl9CgkJZXh0ZXJuYWwuaW52b2tlKEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpKTsKCX0KCglmdW5jdGlvbiBsb2dEZWJ1ZyhtZXNzYWdlKSB7CgkJc2VuZExvZ01lc3NhZ2UoImRlYnVnIiwgbWVzc2FnZSk7Cgl9CglmdW5jdGlvbiBsb2dJbmZvKG1lc3NhZ2UpIHsKCQlzZW5kTG9nTWVzc2FnZSgiaW5mbyIsIG1lc3NhZ2UpOwoJfQoJZnVuY3Rpb24gbG9nV2FybmluZyhtZXNzYWdlKSB7CgkJc2VuZExvZ01lc3NhZ2UoIndhcm5pbmciLCBtZXNzYWdlKTsKCX0KCWZ1bmN0aW9uIGxvZ0Vycm9yKG1lc3NhZ2UpIHsKCQlzZW5kTG9nTWVzc2FnZSgiZXJyb3IiLCBtZXNzYWdlKTsKCX0KCWZ1bmN0aW9uIGxvZ0ZhdGFsKG1lc3NhZ2UpIHsKCQlzZW5kTG9nTWVzc2FnZSgiZmF0YWwiLCBtZXNzYWdlKTsKCX0KCgl3aW5kb3cud2FpbHMubG9nID0gewoJCWRlYnVnOiBsb2dEZWJ1ZywKCQlpbmZvOiBsb2dJbmZvLAoJCXdhcm5pbmc6IGxvZ1dhcm5pbmcsCgkJZXJyb3I6IGxvZ0Vycm9yLAoJCWZhdGFsOiBsb2dGYXRhbCwKCX07CgoJLyoqKioqKioqKioqKioqKioqKioqKioqKioqIEV4cG9ydHMgKioqKioqKioqKioqKioqKioqKioqKioqKi8KCgl3aW5kb3cud2FpbHMuXyA9IHsKCQluZXdCaW5kaW5nOiBuZXdCaW5kaW5nLAoJCWNhbGxiYWNrOiBjYWxsYmFjaywKCQlub3RpZnk6IG5vdGlmeSwKCQlzZW5kTG9nTWVzc2FnZTogc2VuZExvZ01lc3NhZ2UsCgkJY2FsbGJhY2tzOiBjYWxsYmFja3MsCgkJaW5qZWN0Q1NTOiBpbmplY3RDU1MsCgkJYWRkU2NyaXB0OiBhZGRTY3JpcHQsCgkJc2V0RG9jdW1lbnQ6IHNldERvY3VtZW50LAoJfQoKCS8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovCgoJLy8gTm90aWZ5IGJhY2tlbmQgdGhhdCB0aGUgcnVudGltZSBoYXMgZmluaXNoZWQgbG9hZGluZwoJd2luZG93LndhaWxzLmV2ZW50cy5lbWl0KCJ3YWlsczpsb2FkZWQiKTsKCn0pKCk=\"") + packr.PackJSONBytes("./assets/default", "default.html", "\"PGRpdiBpZD0iYXBwIj48L2Rpdj4=\"") + packr.PackJSONBytes("./assets/default", "jquery.3.3.1.min.js", "\"LyohIGpRdWVyeSB2My4zLjEgLWFqYXgsLWFqYXgvanNvbnAsLWFqYXgvbG9hZCwtYWpheC9wYXJzZVhNTCwtYWpheC9zY3JpcHQsLWFqYXgvdmFyL2xvY2F0aW9uLC1hamF4L3Zhci9ub25jZSwtYWpheC92YXIvcnF1ZXJ5LC1hamF4L3hociwtbWFuaXB1bGF0aW9uL19ldmFsVXJsLC1ldmVudC9hamF4LC1lZmZlY3RzLC1lZmZlY3RzL1R3ZWVuLC1lZmZlY3RzL2FuaW1hdGVkU2VsZWN0b3IgfCAoYykgSlMgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzIHwganF1ZXJ5Lm9yZy9saWNlbnNlICovCiFmdW5jdGlvbiAoZSwgdCkgeyAidXNlIHN0cmljdCI7ICJvYmplY3QiID09IHR5cGVvZiBtb2R1bGUgJiYgIm9iamVjdCIgPT0gdHlwZW9mIG1vZHVsZS5leHBvcnRzID8gbW9kdWxlLmV4cG9ydHMgPSBlLmRvY3VtZW50ID8gdChlLCAhMCkgOiBmdW5jdGlvbiAoZSkgeyBpZiAoIWUuZG9jdW1lbnQpIHRocm93IG5ldyBFcnJvcigialF1ZXJ5IHJlcXVpcmVzIGEgd2luZG93IHdpdGggYSBkb2N1bWVudCIpOyByZXR1cm4gdChlKSB9IDogdChlKSB9KCJ1bmRlZmluZWQiICE9IHR5cGVvZiB3aW5kb3cgPyB3aW5kb3cgOiB0aGlzLCBmdW5jdGlvbiAoZSwgdCkgeyAidXNlIHN0cmljdCI7IHZhciBuID0gW10sIHIgPSBlLmRvY3VtZW50LCBpID0gT2JqZWN0LmdldFByb3RvdHlwZU9mLCBvID0gbi5zbGljZSwgYSA9IG4uY29uY2F0LCB1ID0gbi5wdXNoLCBzID0gbi5pbmRleE9mLCBsID0ge30sIGMgPSBsLnRvU3RyaW5nLCBmID0gbC5oYXNPd25Qcm9wZXJ0eSwgZCA9IGYudG9TdHJpbmcsIHAgPSBkLmNhbGwoT2JqZWN0KSwgaCA9IHt9LCBnID0gZnVuY3Rpb24gZSh0KSB7IHJldHVybiAiZnVuY3Rpb24iID09IHR5cGVvZiB0ICYmICJudW1iZXIiICE9IHR5cGVvZiB0Lm5vZGVUeXBlIH0sIHYgPSBmdW5jdGlvbiBlKHQpIHsgcmV0dXJuIG51bGwgIT0gdCAmJiB0ID09PSB0LndpbmRvdyB9LCB5ID0geyB0eXBlOiAhMCwgc3JjOiAhMCwgbm9Nb2R1bGU6ICEwIH07IGZ1bmN0aW9uIG0oZSwgdCwgbikgeyB2YXIgaSwgbyA9ICh0ID0gdCB8fCByKS5jcmVhdGVFbGVtZW50KCJzY3JpcHQiKTsgaWYgKG8udGV4dCA9IGUsIG4pIGZvciAoaSBpbiB5KSBuW2ldICYmIChvW2ldID0gbltpXSk7IHQuaGVhZC5hcHBlbmRDaGlsZChvKS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKG8pIH0gZnVuY3Rpb24gYihlKSB7IHJldHVybiBudWxsID09IGUgPyBlICsgIiIgOiAib2JqZWN0IiA9PSB0eXBlb2YgZSB8fCAiZnVuY3Rpb24iID09IHR5cGVvZiBlID8gbFtjLmNhbGwoZSldIHx8ICJvYmplY3QiIDogdHlwZW9mIGUgfSB2YXIgeCA9ICIzLjMuMSAtYWpheCwtYWpheC9qc29ucCwtYWpheC9sb2FkLC1hamF4L3BhcnNlWE1MLC1hamF4L3NjcmlwdCwtYWpheC92YXIvbG9jYXRpb24sLWFqYXgvdmFyL25vbmNlLC1hamF4L3Zhci9ycXVlcnksLWFqYXgveGhyLC1tYW5pcHVsYXRpb24vX2V2YWxVcmwsLWV2ZW50L2FqYXgsLWVmZmVjdHMsLWVmZmVjdHMvVHdlZW4sLWVmZmVjdHMvYW5pbWF0ZWRTZWxlY3RvciIsIHcgPSBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gbmV3IHcuZm4uaW5pdChlLCB0KSB9LCBDID0gL15bXHNcdUZFRkZceEEwXSt8W1xzXHVGRUZGXHhBMF0rJC9nOyB3LmZuID0gdy5wcm90b3R5cGUgPSB7IGpxdWVyeTogeCwgY29uc3RydWN0b3I6IHcsIGxlbmd0aDogMCwgdG9BcnJheTogZnVuY3Rpb24gKCkgeyByZXR1cm4gby5jYWxsKHRoaXMpIH0sIGdldDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIG51bGwgPT0gZSA/IG8uY2FsbCh0aGlzKSA6IGUgPCAwID8gdGhpc1tlICsgdGhpcy5sZW5ndGhdIDogdGhpc1tlXSB9LCBwdXNoU3RhY2s6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gdy5tZXJnZSh0aGlzLmNvbnN0cnVjdG9yKCksIGUpOyByZXR1cm4gdC5wcmV2T2JqZWN0ID0gdGhpcywgdCB9LCBlYWNoOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdy5lYWNoKHRoaXMsIGUpIH0sIG1hcDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHRoaXMucHVzaFN0YWNrKHcubWFwKHRoaXMsIGZ1bmN0aW9uICh0LCBuKSB7IHJldHVybiBlLmNhbGwodCwgbiwgdCkgfSkpIH0sIHNsaWNlOiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLnB1c2hTdGFjayhvLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykpIH0sIGZpcnN0OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLmVxKDApIH0sIGxhc3Q6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMuZXEoLTEpIH0sIGVxOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IHRoaXMubGVuZ3RoLCBuID0gK2UgKyAoZSA8IDAgPyB0IDogMCk7IHJldHVybiB0aGlzLnB1c2hTdGFjayhuID49IDAgJiYgbiA8IHQgPyBbdGhpc1tuXV0gOiBbXSkgfSwgZW5kOiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLnByZXZPYmplY3QgfHwgdGhpcy5jb25zdHJ1Y3RvcigpIH0sIHB1c2g6IHUsIHNvcnQ6IG4uc29ydCwgc3BsaWNlOiBuLnNwbGljZSB9LCB3LmV4dGVuZCA9IHcuZm4uZXh0ZW5kID0gZnVuY3Rpb24gKCkgeyB2YXIgZSwgdCwgbiwgciwgaSwgbywgYSA9IGFyZ3VtZW50c1swXSB8fCB7fSwgdSA9IDEsIHMgPSBhcmd1bWVudHMubGVuZ3RoLCBsID0gITE7IGZvciAoImJvb2xlYW4iID09IHR5cGVvZiBhICYmIChsID0gYSwgYSA9IGFyZ3VtZW50c1t1XSB8fCB7fSwgdSsrKSwgIm9iamVjdCIgPT0gdHlwZW9mIGEgfHwgZyhhKSB8fCAoYSA9IHt9KSwgdSA9PT0gcyAmJiAoYSA9IHRoaXMsIHUtLSk7IHUgPCBzOyB1KyspaWYgKG51bGwgIT0gKGUgPSBhcmd1bWVudHNbdV0pKSBmb3IgKHQgaW4gZSkgbiA9IGFbdF0sIGEgIT09IChyID0gZVt0XSkgJiYgKGwgJiYgciAmJiAody5pc1BsYWluT2JqZWN0KHIpIHx8IChpID0gQXJyYXkuaXNBcnJheShyKSkpID8gKGkgPyAoaSA9ICExLCBvID0gbiAmJiBBcnJheS5pc0FycmF5KG4pID8gbiA6IFtdKSA6IG8gPSBuICYmIHcuaXNQbGFpbk9iamVjdChuKSA/IG4gOiB7fSwgYVt0XSA9IHcuZXh0ZW5kKGwsIG8sIHIpKSA6IHZvaWQgMCAhPT0gciAmJiAoYVt0XSA9IHIpKTsgcmV0dXJuIGEgfSwgdy5leHRlbmQoeyBleHBhbmRvOiAialF1ZXJ5IiArICh4ICsgTWF0aC5yYW5kb20oKSkucmVwbGFjZSgvXEQvZywgIiIpLCBpc1JlYWR5OiAhMCwgZXJyb3I6IGZ1bmN0aW9uIChlKSB7IHRocm93IG5ldyBFcnJvcihlKSB9LCBub29wOiBmdW5jdGlvbiAoKSB7IH0sIGlzUGxhaW5PYmplY3Q6IGZ1bmN0aW9uIChlKSB7IHZhciB0LCBuOyByZXR1cm4gISghZSB8fCAiW29iamVjdCBPYmplY3RdIiAhPT0gYy5jYWxsKGUpKSAmJiAoISh0ID0gaShlKSkgfHwgImZ1bmN0aW9uIiA9PSB0eXBlb2YgKG4gPSBmLmNhbGwodCwgImNvbnN0cnVjdG9yIikgJiYgdC5jb25zdHJ1Y3RvcikgJiYgZC5jYWxsKG4pID09PSBwKSB9LCBpc0VtcHR5T2JqZWN0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdDsgZm9yICh0IGluIGUpIHJldHVybiAhMTsgcmV0dXJuICEwIH0sIGdsb2JhbEV2YWw6IGZ1bmN0aW9uIChlKSB7IG0oZSkgfSwgZWFjaDogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIgPSAwOyBpZiAoVChlKSkgeyBmb3IgKG4gPSBlLmxlbmd0aDsgciA8IG47IHIrKylpZiAoITEgPT09IHQuY2FsbChlW3JdLCByLCBlW3JdKSkgYnJlYWsgfSBlbHNlIGZvciAociBpbiBlKSBpZiAoITEgPT09IHQuY2FsbChlW3JdLCByLCBlW3JdKSkgYnJlYWs7IHJldHVybiBlIH0sIHRyaW06IGZ1bmN0aW9uIChlKSB7IHJldHVybiBudWxsID09IGUgPyAiIiA6IChlICsgIiIpLnJlcGxhY2UoQywgIiIpIH0sIG1ha2VBcnJheTogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4gPSB0IHx8IFtdOyByZXR1cm4gbnVsbCAhPSBlICYmIChUKE9iamVjdChlKSkgPyB3Lm1lcmdlKG4sICJzdHJpbmciID09IHR5cGVvZiBlID8gW2VdIDogZSkgOiB1LmNhbGwobiwgZSkpLCBuIH0sIGluQXJyYXk6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBudWxsID09IHQgPyAtMSA6IHMuY2FsbCh0LCBlLCBuKSB9LCBtZXJnZTogZnVuY3Rpb24gKGUsIHQpIHsgZm9yICh2YXIgbiA9ICt0Lmxlbmd0aCwgciA9IDAsIGkgPSBlLmxlbmd0aDsgciA8IG47IHIrKyllW2krK10gPSB0W3JdOyByZXR1cm4gZS5sZW5ndGggPSBpLCBlIH0sIGdyZXA6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IGZvciAodmFyIHIsIGkgPSBbXSwgbyA9IDAsIGEgPSBlLmxlbmd0aCwgdSA9ICFuOyBvIDwgYTsgbysrKShyID0gIXQoZVtvXSwgbykpICE9PSB1ICYmIGkucHVzaChlW29dKTsgcmV0dXJuIGkgfSwgbWFwOiBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciwgaSwgbyA9IDAsIHUgPSBbXTsgaWYgKFQoZSkpIGZvciAociA9IGUubGVuZ3RoOyBvIDwgcjsgbysrKW51bGwgIT0gKGkgPSB0KGVbb10sIG8sIG4pKSAmJiB1LnB1c2goaSk7IGVsc2UgZm9yIChvIGluIGUpIG51bGwgIT0gKGkgPSB0KGVbb10sIG8sIG4pKSAmJiB1LnB1c2goaSk7IHJldHVybiBhLmFwcGx5KFtdLCB1KSB9LCBndWlkOiAxLCBzdXBwb3J0OiBoIH0pLCAiZnVuY3Rpb24iID09IHR5cGVvZiBTeW1ib2wgJiYgKHcuZm5bU3ltYm9sLml0ZXJhdG9yXSA9IG5bU3ltYm9sLml0ZXJhdG9yXSksIHcuZWFjaCgiQm9vbGVhbiBOdW1iZXIgU3RyaW5nIEZ1bmN0aW9uIEFycmF5IERhdGUgUmVnRXhwIE9iamVjdCBFcnJvciBTeW1ib2wiLnNwbGl0KCIgIiksIGZ1bmN0aW9uIChlLCB0KSB7IGxbIltvYmplY3QgIiArIHQgKyAiXSJdID0gdC50b0xvd2VyQ2FzZSgpIH0pOyBmdW5jdGlvbiBUKGUpIHsgdmFyIHQgPSAhIWUgJiYgImxlbmd0aCIgaW4gZSAmJiBlLmxlbmd0aCwgbiA9IGIoZSk7IHJldHVybiAhZyhlKSAmJiAhdihlKSAmJiAoImFycmF5IiA9PT0gbiB8fCAwID09PSB0IHx8ICJudW1iZXIiID09IHR5cGVvZiB0ICYmIHQgPiAwICYmIHQgLSAxIGluIGUpIH0gdmFyIEUgPSBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgbiwgciwgaSwgbywgYSwgdSwgcywgbCwgYywgZiwgZCwgcCwgaCwgZywgdiwgeSwgbSwgYiwgeCA9ICJzaXp6bGUiICsgMSAqIG5ldyBEYXRlLCB3ID0gZS5kb2N1bWVudCwgQyA9IDAsIFQgPSAwLCBFID0gYWUoKSwgTiA9IGFlKCksIGsgPSBhZSgpLCBBID0gZnVuY3Rpb24gKGUsIHQpIHsgcmV0dXJuIGUgPT09IHQgJiYgKGYgPSAhMCksIDAgfSwgRCA9IHt9Lmhhc093blByb3BlcnR5LCBTID0gW10sIEwgPSBTLnBvcCwgaiA9IFMucHVzaCwgcSA9IFMucHVzaCwgTyA9IFMuc2xpY2UsIFAgPSBmdW5jdGlvbiAoZSwgdCkgeyBmb3IgKHZhciBuID0gMCwgciA9IGUubGVuZ3RoOyBuIDwgcjsgbisrKWlmIChlW25dID09PSB0KSByZXR1cm4gbjsgcmV0dXJuIC0xIH0sIEggPSAiY2hlY2tlZHxzZWxlY3RlZHxhc3luY3xhdXRvZm9jdXN8YXV0b3BsYXl8Y29udHJvbHN8ZGVmZXJ8ZGlzYWJsZWR8aGlkZGVufGlzbWFwfGxvb3B8bXVsdGlwbGV8b3BlbnxyZWFkb25seXxyZXF1aXJlZHxzY29wZWQiLCBJID0gIltcXHgyMFxcdFxcclxcblxcZl0iLCBSID0gIig/OlxcXFwufFtcXHctXXxbXlwwLVxceGEwXSkrIiwgQiA9ICJcXFsiICsgSSArICIqKCIgKyBSICsgIikoPzoiICsgSSArICIqKFsqXiR8IX5dPz0pIiArIEkgKyAiKig/OicoKD86XFxcXC58W15cXFxcJ10pKiknfFwiKCg/OlxcXFwufFteXFxcXFwiXSkqKVwifCgiICsgUiArICIpKXwpIiArIEkgKyAiKlxcXSIsIE0gPSAiOigiICsgUiArICIpKD86XFwoKCgnKCg/OlxcXFwufFteXFxcXCddKSopJ3xcIigoPzpcXFxcLnxbXlxcXFxcIl0pKilcIil8KCg/OlxcXFwufFteXFxcXCgpW1xcXV18IiArIEIgKyAiKSopfC4qKVxcKXwpIiwgVyA9IG5ldyBSZWdFeHAoSSArICIrIiwgImciKSwgJCA9IG5ldyBSZWdFeHAoIl4iICsgSSArICIrfCgoPzpefFteXFxcXF0pKD86XFxcXC4pKikiICsgSSArICIrJCIsICJnIiksIEYgPSBuZXcgUmVnRXhwKCJeIiArIEkgKyAiKiwiICsgSSArICIqIiksIHogPSBuZXcgUmVnRXhwKCJeIiArIEkgKyAiKihbPit+XXwiICsgSSArICIpIiArIEkgKyAiKiIpLCBfID0gbmV3IFJlZ0V4cCgiPSIgKyBJICsgIiooW15cXF0nXCJdKj8pIiArIEkgKyAiKlxcXSIsICJnIiksIFUgPSBuZXcgUmVnRXhwKE0pLCBWID0gbmV3IFJlZ0V4cCgiXiIgKyBSICsgIiQiKSwgWCA9IHsgSUQ6IG5ldyBSZWdFeHAoIl4jKCIgKyBSICsgIikiKSwgQ0xBU1M6IG5ldyBSZWdFeHAoIl5cXC4oIiArIFIgKyAiKSIpLCBUQUc6IG5ldyBSZWdFeHAoIl4oIiArIFIgKyAifFsqXSkiKSwgQVRUUjogbmV3IFJlZ0V4cCgiXiIgKyBCKSwgUFNFVURPOiBuZXcgUmVnRXhwKCJeIiArIE0pLCBDSElMRDogbmV3IFJlZ0V4cCgiXjoob25seXxmaXJzdHxsYXN0fG50aHxudGgtbGFzdCktKGNoaWxkfG9mLXR5cGUpKD86XFwoIiArIEkgKyAiKihldmVufG9kZHwoKFsrLV18KShcXGQqKW58KSIgKyBJICsgIiooPzooWystXXwpIiArIEkgKyAiKihcXGQrKXwpKSIgKyBJICsgIipcXCl8KSIsICJpIiksIGJvb2w6IG5ldyBSZWdFeHAoIl4oPzoiICsgSCArICIpJCIsICJpIiksIG5lZWRzQ29udGV4dDogbmV3IFJlZ0V4cCgiXiIgKyBJICsgIipbPit+XXw6KGV2ZW58b2RkfGVxfGd0fGx0fG50aHxmaXJzdHxsYXN0KSg/OlxcKCIgKyBJICsgIiooKD86LVxcZCk/XFxkKikiICsgSSArICIqXFwpfCkoPz1bXi1dfCQpIiwgImkiKSB9LCBRID0gL14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWF8YnV0dG9uKSQvaSwgWSA9IC9eaFxkJC9pLCBHID0gL15bXntdK1x7XHMqXFtuYXRpdmUgXHcvLCBLID0gL14oPzojKFtcdy1dKyl8KFx3Kyl8XC4oW1x3LV0rKSkkLywgSiA9IC9bK35dLywgWiA9IG5ldyBSZWdFeHAoIlxcXFwoW1xcZGEtZl17MSw2fSIgKyBJICsgIj98KCIgKyBJICsgIil8LikiLCAiaWciKSwgZWUgPSBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciA9ICIweCIgKyB0IC0gNjU1MzY7IHJldHVybiByICE9PSByIHx8IG4gPyB0IDogciA8IDAgPyBTdHJpbmcuZnJvbUNoYXJDb2RlKHIgKyA2NTUzNikgOiBTdHJpbmcuZnJvbUNoYXJDb2RlKHIgPj4gMTAgfCA1NTI5NiwgMTAyMyAmIHIgfCA1NjMyMCkgfSwgdGUgPSAvKFtcMC1ceDFmXHg3Zl18Xi0/XGQpfF4tJHxbXlwwLVx4MWZceDdmLVx1RkZGRlx3LV0vZywgbmUgPSBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gdCA/ICJcMCIgPT09IGUgPyAiXHVmZmZkIiA6IGUuc2xpY2UoMCwgLTEpICsgIlxcIiArIGUuY2hhckNvZGVBdChlLmxlbmd0aCAtIDEpLnRvU3RyaW5nKDE2KSArICIgIiA6ICJcXCIgKyBlIH0sIHJlID0gZnVuY3Rpb24gKCkgeyBkKCkgfSwgaWUgPSBtZShmdW5jdGlvbiAoZSkgeyByZXR1cm4gITAgPT09IGUuZGlzYWJsZWQgJiYgKCJmb3JtIiBpbiBlIHx8ICJsYWJlbCIgaW4gZSkgfSwgeyBkaXI6ICJwYXJlbnROb2RlIiwgbmV4dDogImxlZ2VuZCIgfSk7IHRyeSB7IHEuYXBwbHkoUyA9IE8uY2FsbCh3LmNoaWxkTm9kZXMpLCB3LmNoaWxkTm9kZXMpLCBTW3cuY2hpbGROb2Rlcy5sZW5ndGhdLm5vZGVUeXBlIH0gY2F0Y2ggKGUpIHsgcSA9IHsgYXBwbHk6IFMubGVuZ3RoID8gZnVuY3Rpb24gKGUsIHQpIHsgai5hcHBseShlLCBPLmNhbGwodCkpIH0gOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IGUubGVuZ3RoLCByID0gMDsgd2hpbGUgKGVbbisrXSA9IHRbcisrXSk7IGUubGVuZ3RoID0gbiAtIDEgfSB9IH0gZnVuY3Rpb24gb2UoZSwgdCwgciwgaSkgeyB2YXIgbywgdSwgbCwgYywgZiwgaCwgeSwgbSA9IHQgJiYgdC5vd25lckRvY3VtZW50LCBDID0gdCA/IHQubm9kZVR5cGUgOiA5OyBpZiAociA9IHIgfHwgW10sICJzdHJpbmciICE9IHR5cGVvZiBlIHx8ICFlIHx8IDEgIT09IEMgJiYgOSAhPT0gQyAmJiAxMSAhPT0gQykgcmV0dXJuIHI7IGlmICghaSAmJiAoKHQgPyB0Lm93bmVyRG9jdW1lbnQgfHwgdCA6IHcpICE9PSBwICYmIGQodCksIHQgPSB0IHx8IHAsIGcpKSB7IGlmICgxMSAhPT0gQyAmJiAoZiA9IEsuZXhlYyhlKSkpIGlmIChvID0gZlsxXSkgeyBpZiAoOSA9PT0gQykgeyBpZiAoIShsID0gdC5nZXRFbGVtZW50QnlJZChvKSkpIHJldHVybiByOyBpZiAobC5pZCA9PT0gbykgcmV0dXJuIHIucHVzaChsKSwgciB9IGVsc2UgaWYgKG0gJiYgKGwgPSBtLmdldEVsZW1lbnRCeUlkKG8pKSAmJiBiKHQsIGwpICYmIGwuaWQgPT09IG8pIHJldHVybiByLnB1c2gobCksIHIgfSBlbHNlIHsgaWYgKGZbMl0pIHJldHVybiBxLmFwcGx5KHIsIHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoZSkpLCByOyBpZiAoKG8gPSBmWzNdKSAmJiBuLmdldEVsZW1lbnRzQnlDbGFzc05hbWUgJiYgdC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKSByZXR1cm4gcS5hcHBseShyLCB0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUobykpLCByIH0gaWYgKG4ucXNhICYmICFrW2UgKyAiICJdICYmICghdiB8fCAhdi50ZXN0KGUpKSkgeyBpZiAoMSAhPT0gQykgbSA9IHQsIHkgPSBlOyBlbHNlIGlmICgib2JqZWN0IiAhPT0gdC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpKSB7IChjID0gdC5nZXRBdHRyaWJ1dGUoImlkIikpID8gYyA9IGMucmVwbGFjZSh0ZSwgbmUpIDogdC5zZXRBdHRyaWJ1dGUoImlkIiwgYyA9IHgpLCB1ID0gKGggPSBhKGUpKS5sZW5ndGg7IHdoaWxlICh1LS0pIGhbdV0gPSAiIyIgKyBjICsgIiAiICsgeWUoaFt1XSk7IHkgPSBoLmpvaW4oIiwiKSwgbSA9IEoudGVzdChlKSAmJiBnZSh0LnBhcmVudE5vZGUpIHx8IHQgfSBpZiAoeSkgdHJ5IHsgcmV0dXJuIHEuYXBwbHkociwgbS5xdWVyeVNlbGVjdG9yQWxsKHkpKSwgciB9IGNhdGNoIChlKSB7IH0gZmluYWxseSB7IGMgPT09IHggJiYgdC5yZW1vdmVBdHRyaWJ1dGUoImlkIikgfSB9IH0gcmV0dXJuIHMoZS5yZXBsYWNlKCQsICIkMSIpLCB0LCByLCBpKSB9IGZ1bmN0aW9uIGFlKCkgeyB2YXIgZSA9IFtdOyBmdW5jdGlvbiB0KG4sIGkpIHsgcmV0dXJuIGUucHVzaChuICsgIiAiKSA+IHIuY2FjaGVMZW5ndGggJiYgZGVsZXRlIHRbZS5zaGlmdCgpXSwgdFtuICsgIiAiXSA9IGkgfSByZXR1cm4gdCB9IGZ1bmN0aW9uIHVlKGUpIHsgcmV0dXJuIGVbeF0gPSAhMCwgZSB9IGZ1bmN0aW9uIHNlKGUpIHsgdmFyIHQgPSBwLmNyZWF0ZUVsZW1lbnQoImZpZWxkc2V0Iik7IHRyeSB7IHJldHVybiAhIWUodCkgfSBjYXRjaCAoZSkgeyByZXR1cm4gITEgfSBmaW5hbGx5IHsgdC5wYXJlbnROb2RlICYmIHQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0KSwgdCA9IG51bGwgfSB9IGZ1bmN0aW9uIGxlKGUsIHQpIHsgdmFyIG4gPSBlLnNwbGl0KCJ8IiksIGkgPSBuLmxlbmd0aDsgd2hpbGUgKGktLSkgci5hdHRySGFuZGxlW25baV1dID0gdCB9IGZ1bmN0aW9uIGNlKGUsIHQpIHsgdmFyIG4gPSB0ICYmIGUsIHIgPSBuICYmIDEgPT09IGUubm9kZVR5cGUgJiYgMSA9PT0gdC5ub2RlVHlwZSAmJiBlLnNvdXJjZUluZGV4IC0gdC5zb3VyY2VJbmRleDsgaWYgKHIpIHJldHVybiByOyBpZiAobikgd2hpbGUgKG4gPSBuLm5leHRTaWJsaW5nKSBpZiAobiA9PT0gdCkgcmV0dXJuIC0xOyByZXR1cm4gZSA/IDEgOiAtMSB9IGZ1bmN0aW9uIGZlKGUpIHsgcmV0dXJuIGZ1bmN0aW9uICh0KSB7IHJldHVybiAiaW5wdXQiID09PSB0Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgJiYgdC50eXBlID09PSBlIH0gfSBmdW5jdGlvbiBkZShlKSB7IHJldHVybiBmdW5jdGlvbiAodCkgeyB2YXIgbiA9IHQubm9kZU5hbWUudG9Mb3dlckNhc2UoKTsgcmV0dXJuICgiaW5wdXQiID09PSBuIHx8ICJidXR0b24iID09PSBuKSAmJiB0LnR5cGUgPT09IGUgfSB9IGZ1bmN0aW9uIHBlKGUpIHsgcmV0dXJuIGZ1bmN0aW9uICh0KSB7IHJldHVybiAiZm9ybSIgaW4gdCA/IHQucGFyZW50Tm9kZSAmJiAhMSA9PT0gdC5kaXNhYmxlZCA/ICJsYWJlbCIgaW4gdCA/ICJsYWJlbCIgaW4gdC5wYXJlbnROb2RlID8gdC5wYXJlbnROb2RlLmRpc2FibGVkID09PSBlIDogdC5kaXNhYmxlZCA9PT0gZSA6IHQuaXNEaXNhYmxlZCA9PT0gZSB8fCB0LmlzRGlzYWJsZWQgIT09ICFlICYmIGllKHQpID09PSBlIDogdC5kaXNhYmxlZCA9PT0gZSA6ICJsYWJlbCIgaW4gdCAmJiB0LmRpc2FibGVkID09PSBlIH0gfSBmdW5jdGlvbiBoZShlKSB7IHJldHVybiB1ZShmdW5jdGlvbiAodCkgeyByZXR1cm4gdCA9ICt0LCB1ZShmdW5jdGlvbiAobiwgcikgeyB2YXIgaSwgbyA9IGUoW10sIG4ubGVuZ3RoLCB0KSwgYSA9IG8ubGVuZ3RoOyB3aGlsZSAoYS0tKSBuW2kgPSBvW2FdXSAmJiAobltpXSA9ICEocltpXSA9IG5baV0pKSB9KSB9KSB9IGZ1bmN0aW9uIGdlKGUpIHsgcmV0dXJuIGUgJiYgInVuZGVmaW5lZCIgIT0gdHlwZW9mIGUuZ2V0RWxlbWVudHNCeVRhZ05hbWUgJiYgZSB9IG4gPSBvZS5zdXBwb3J0ID0ge30sIG8gPSBvZS5pc1hNTCA9IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZSAmJiAoZS5vd25lckRvY3VtZW50IHx8IGUpLmRvY3VtZW50RWxlbWVudDsgcmV0dXJuICEhdCAmJiAiSFRNTCIgIT09IHQubm9kZU5hbWUgfSwgZCA9IG9lLnNldERvY3VtZW50ID0gZnVuY3Rpb24gKGUpIHsgdmFyIHQsIGksIGEgPSBlID8gZS5vd25lckRvY3VtZW50IHx8IGUgOiB3OyByZXR1cm4gYSAhPT0gcCAmJiA5ID09PSBhLm5vZGVUeXBlICYmIGEuZG9jdW1lbnRFbGVtZW50ID8gKHAgPSBhLCBoID0gcC5kb2N1bWVudEVsZW1lbnQsIGcgPSAhbyhwKSwgdyAhPT0gcCAmJiAoaSA9IHAuZGVmYXVsdFZpZXcpICYmIGkudG9wICE9PSBpICYmIChpLmFkZEV2ZW50TGlzdGVuZXIgPyBpLmFkZEV2ZW50TGlzdGVuZXIoInVubG9hZCIsIHJlLCAhMSkgOiBpLmF0dGFjaEV2ZW50ICYmIGkuYXR0YWNoRXZlbnQoIm9udW5sb2FkIiwgcmUpKSwgbi5hdHRyaWJ1dGVzID0gc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUuY2xhc3NOYW1lID0gImkiLCAhZS5nZXRBdHRyaWJ1dGUoImNsYXNzTmFtZSIpIH0pLCBuLmdldEVsZW1lbnRzQnlUYWdOYW1lID0gc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUuYXBwZW5kQ2hpbGQocC5jcmVhdGVDb21tZW50KCIiKSksICFlLmdldEVsZW1lbnRzQnlUYWdOYW1lKCIqIikubGVuZ3RoIH0pLCBuLmdldEVsZW1lbnRzQnlDbGFzc05hbWUgPSBHLnRlc3QocC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKSwgbi5nZXRCeUlkID0gc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGguYXBwZW5kQ2hpbGQoZSkuaWQgPSB4LCAhcC5nZXRFbGVtZW50c0J5TmFtZSB8fCAhcC5nZXRFbGVtZW50c0J5TmFtZSh4KS5sZW5ndGggfSksIG4uZ2V0QnlJZCA/IChyLmZpbHRlci5JRCA9IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZS5yZXBsYWNlKFosIGVlKTsgcmV0dXJuIGZ1bmN0aW9uIChlKSB7IHJldHVybiBlLmdldEF0dHJpYnV0ZSgiaWQiKSA9PT0gdCB9IH0sIHIuZmluZC5JRCA9IGZ1bmN0aW9uIChlLCB0KSB7IGlmICgidW5kZWZpbmVkIiAhPSB0eXBlb2YgdC5nZXRFbGVtZW50QnlJZCAmJiBnKSB7IHZhciBuID0gdC5nZXRFbGVtZW50QnlJZChlKTsgcmV0dXJuIG4gPyBbbl0gOiBbXSB9IH0pIDogKHIuZmlsdGVyLklEID0gZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSBlLnJlcGxhY2UoWiwgZWUpOyByZXR1cm4gZnVuY3Rpb24gKGUpIHsgdmFyIG4gPSAidW5kZWZpbmVkIiAhPSB0eXBlb2YgZS5nZXRBdHRyaWJ1dGVOb2RlICYmIGUuZ2V0QXR0cmlidXRlTm9kZSgiaWQiKTsgcmV0dXJuIG4gJiYgbi52YWx1ZSA9PT0gdCB9IH0sIHIuZmluZC5JRCA9IGZ1bmN0aW9uIChlLCB0KSB7IGlmICgidW5kZWZpbmVkIiAhPSB0eXBlb2YgdC5nZXRFbGVtZW50QnlJZCAmJiBnKSB7IHZhciBuLCByLCBpLCBvID0gdC5nZXRFbGVtZW50QnlJZChlKTsgaWYgKG8pIHsgaWYgKChuID0gby5nZXRBdHRyaWJ1dGVOb2RlKCJpZCIpKSAmJiBuLnZhbHVlID09PSBlKSByZXR1cm4gW29dOyBpID0gdC5nZXRFbGVtZW50c0J5TmFtZShlKSwgciA9IDA7IHdoaWxlIChvID0gaVtyKytdKSBpZiAoKG4gPSBvLmdldEF0dHJpYnV0ZU5vZGUoImlkIikpICYmIG4udmFsdWUgPT09IGUpIHJldHVybiBbb10gfSByZXR1cm4gW10gfSB9KSwgci5maW5kLlRBRyA9IG4uZ2V0RWxlbWVudHNCeVRhZ05hbWUgPyBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gInVuZGVmaW5lZCIgIT0gdHlwZW9mIHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUgPyB0LmdldEVsZW1lbnRzQnlUYWdOYW1lKGUpIDogbi5xc2EgPyB0LnF1ZXJ5U2VsZWN0b3JBbGwoZSkgOiB2b2lkIDAgfSA6IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCByID0gW10sIGkgPSAwLCBvID0gdC5nZXRFbGVtZW50c0J5VGFnTmFtZShlKTsgaWYgKCIqIiA9PT0gZSkgeyB3aGlsZSAobiA9IG9baSsrXSkgMSA9PT0gbi5ub2RlVHlwZSAmJiByLnB1c2gobik7IHJldHVybiByIH0gcmV0dXJuIG8gfSwgci5maW5kLkNMQVNTID0gbi5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lICYmIGZ1bmN0aW9uIChlLCB0KSB7IGlmICgidW5kZWZpbmVkIiAhPSB0eXBlb2YgdC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lICYmIGcpIHJldHVybiB0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoZSkgfSwgeSA9IFtdLCB2ID0gW10sIChuLnFzYSA9IEcudGVzdChwLnF1ZXJ5U2VsZWN0b3JBbGwpKSAmJiAoc2UoZnVuY3Rpb24gKGUpIHsgaC5hcHBlbmRDaGlsZChlKS5pbm5lckhUTUwgPSAiPGEgaWQ9JyIgKyB4ICsgIic+PC9hPjxzZWxlY3QgaWQ9JyIgKyB4ICsgIi1cclxcJyBtc2FsbG93Y2FwdHVyZT0nJz48b3B0aW9uIHNlbGVjdGVkPScnPjwvb3B0aW9uPjwvc2VsZWN0PiIsIGUucXVlcnlTZWxlY3RvckFsbCgiW21zYWxsb3djYXB0dXJlXj0nJ10iKS5sZW5ndGggJiYgdi5wdXNoKCJbKl4kXT0iICsgSSArICIqKD86Jyd8XCJcIikiKSwgZS5xdWVyeVNlbGVjdG9yQWxsKCJbc2VsZWN0ZWRdIikubGVuZ3RoIHx8IHYucHVzaCgiXFxbIiArIEkgKyAiKig/OnZhbHVlfCIgKyBIICsgIikiKSwgZS5xdWVyeVNlbGVjdG9yQWxsKCJbaWR+PSIgKyB4ICsgIi1dIikubGVuZ3RoIHx8IHYucHVzaCgifj0iKSwgZS5xdWVyeVNlbGVjdG9yQWxsKCI6Y2hlY2tlZCIpLmxlbmd0aCB8fCB2LnB1c2goIjpjaGVja2VkIiksIGUucXVlcnlTZWxlY3RvckFsbCgiYSMiICsgeCArICIrKiIpLmxlbmd0aCB8fCB2LnB1c2goIi4jLitbK35dIikgfSksIHNlKGZ1bmN0aW9uIChlKSB7IGUuaW5uZXJIVE1MID0gIjxhIGhyZWY9JycgZGlzYWJsZWQ9J2Rpc2FibGVkJz48L2E+PHNlbGVjdCBkaXNhYmxlZD0nZGlzYWJsZWQnPjxvcHRpb24vPjwvc2VsZWN0PiI7IHZhciB0ID0gcC5jcmVhdGVFbGVtZW50KCJpbnB1dCIpOyB0LnNldEF0dHJpYnV0ZSgidHlwZSIsICJoaWRkZW4iKSwgZS5hcHBlbmRDaGlsZCh0KS5zZXRBdHRyaWJ1dGUoIm5hbWUiLCAiRCIpLCBlLnF1ZXJ5U2VsZWN0b3JBbGwoIltuYW1lPWRdIikubGVuZ3RoICYmIHYucHVzaCgibmFtZSIgKyBJICsgIipbKl4kfCF+XT89IiksIDIgIT09IGUucXVlcnlTZWxlY3RvckFsbCgiOmVuYWJsZWQiKS5sZW5ndGggJiYgdi5wdXNoKCI6ZW5hYmxlZCIsICI6ZGlzYWJsZWQiKSwgaC5hcHBlbmRDaGlsZChlKS5kaXNhYmxlZCA9ICEwLCAyICE9PSBlLnF1ZXJ5U2VsZWN0b3JBbGwoIjpkaXNhYmxlZCIpLmxlbmd0aCAmJiB2LnB1c2goIjplbmFibGVkIiwgIjpkaXNhYmxlZCIpLCBlLnF1ZXJ5U2VsZWN0b3JBbGwoIiosOngiKSwgdi5wdXNoKCIsLio6IikgfSkpLCAobi5tYXRjaGVzU2VsZWN0b3IgPSBHLnRlc3QobSA9IGgubWF0Y2hlcyB8fCBoLndlYmtpdE1hdGNoZXNTZWxlY3RvciB8fCBoLm1vek1hdGNoZXNTZWxlY3RvciB8fCBoLm9NYXRjaGVzU2VsZWN0b3IgfHwgaC5tc01hdGNoZXNTZWxlY3RvcikpICYmIHNlKGZ1bmN0aW9uIChlKSB7IG4uZGlzY29ubmVjdGVkTWF0Y2ggPSBtLmNhbGwoZSwgIioiKSwgbS5jYWxsKGUsICJbcyE9JyddOngiKSwgeS5wdXNoKCIhPSIsIE0pIH0pLCB2ID0gdi5sZW5ndGggJiYgbmV3IFJlZ0V4cCh2LmpvaW4oInwiKSksIHkgPSB5Lmxlbmd0aCAmJiBuZXcgUmVnRXhwKHkuam9pbigifCIpKSwgdCA9IEcudGVzdChoLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKSwgYiA9IHQgfHwgRy50ZXN0KGguY29udGFpbnMpID8gZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4gPSA5ID09PSBlLm5vZGVUeXBlID8gZS5kb2N1bWVudEVsZW1lbnQgOiBlLCByID0gdCAmJiB0LnBhcmVudE5vZGU7IHJldHVybiBlID09PSByIHx8ICEoIXIgfHwgMSAhPT0gci5ub2RlVHlwZSB8fCAhKG4uY29udGFpbnMgPyBuLmNvbnRhaW5zKHIpIDogZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiAmJiAxNiAmIGUuY29tcGFyZURvY3VtZW50UG9zaXRpb24ocikpKSB9IDogZnVuY3Rpb24gKGUsIHQpIHsgaWYgKHQpIHdoaWxlICh0ID0gdC5wYXJlbnROb2RlKSBpZiAodCA9PT0gZSkgcmV0dXJuICEwOyByZXR1cm4gITEgfSwgQSA9IHQgPyBmdW5jdGlvbiAoZSwgdCkgeyBpZiAoZSA9PT0gdCkgcmV0dXJuIGYgPSAhMCwgMDsgdmFyIHIgPSAhZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiAtICF0LmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uOyByZXR1cm4gciB8fCAoMSAmIChyID0gKGUub3duZXJEb2N1bWVudCB8fCBlKSA9PT0gKHQub3duZXJEb2N1bWVudCB8fCB0KSA/IGUuY29tcGFyZURvY3VtZW50UG9zaXRpb24odCkgOiAxKSB8fCAhbi5zb3J0RGV0YWNoZWQgJiYgdC5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihlKSA9PT0gciA/IGUgPT09IHAgfHwgZS5vd25lckRvY3VtZW50ID09PSB3ICYmIGIodywgZSkgPyAtMSA6IHQgPT09IHAgfHwgdC5vd25lckRvY3VtZW50ID09PSB3ICYmIGIodywgdCkgPyAxIDogYyA/IFAoYywgZSkgLSBQKGMsIHQpIDogMCA6IDQgJiByID8gLTEgOiAxKSB9IDogZnVuY3Rpb24gKGUsIHQpIHsgaWYgKGUgPT09IHQpIHJldHVybiBmID0gITAsIDA7IHZhciBuLCByID0gMCwgaSA9IGUucGFyZW50Tm9kZSwgbyA9IHQucGFyZW50Tm9kZSwgYSA9IFtlXSwgdSA9IFt0XTsgaWYgKCFpIHx8ICFvKSByZXR1cm4gZSA9PT0gcCA/IC0xIDogdCA9PT0gcCA/IDEgOiBpID8gLTEgOiBvID8gMSA6IGMgPyBQKGMsIGUpIC0gUChjLCB0KSA6IDA7IGlmIChpID09PSBvKSByZXR1cm4gY2UoZSwgdCk7IG4gPSBlOyB3aGlsZSAobiA9IG4ucGFyZW50Tm9kZSkgYS51bnNoaWZ0KG4pOyBuID0gdDsgd2hpbGUgKG4gPSBuLnBhcmVudE5vZGUpIHUudW5zaGlmdChuKTsgd2hpbGUgKGFbcl0gPT09IHVbcl0pIHIrKzsgcmV0dXJuIHIgPyBjZShhW3JdLCB1W3JdKSA6IGFbcl0gPT09IHcgPyAtMSA6IHVbcl0gPT09IHcgPyAxIDogMCB9LCBwKSA6IHAgfSwgb2UubWF0Y2hlcyA9IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiBvZShlLCBudWxsLCBudWxsLCB0KSB9LCBvZS5tYXRjaGVzU2VsZWN0b3IgPSBmdW5jdGlvbiAoZSwgdCkgeyBpZiAoKGUub3duZXJEb2N1bWVudCB8fCBlKSAhPT0gcCAmJiBkKGUpLCB0ID0gdC5yZXBsYWNlKF8sICI9JyQxJ10iKSwgbi5tYXRjaGVzU2VsZWN0b3IgJiYgZyAmJiAha1t0ICsgIiAiXSAmJiAoIXkgfHwgIXkudGVzdCh0KSkgJiYgKCF2IHx8ICF2LnRlc3QodCkpKSB0cnkgeyB2YXIgciA9IG0uY2FsbChlLCB0KTsgaWYgKHIgfHwgbi5kaXNjb25uZWN0ZWRNYXRjaCB8fCBlLmRvY3VtZW50ICYmIDExICE9PSBlLmRvY3VtZW50Lm5vZGVUeXBlKSByZXR1cm4gciB9IGNhdGNoIChlKSB7IH0gcmV0dXJuIG9lKHQsIHAsIG51bGwsIFtlXSkubGVuZ3RoID4gMCB9LCBvZS5jb250YWlucyA9IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiAoZS5vd25lckRvY3VtZW50IHx8IGUpICE9PSBwICYmIGQoZSksIGIoZSwgdCkgfSwgb2UuYXR0ciA9IGZ1bmN0aW9uIChlLCB0KSB7IChlLm93bmVyRG9jdW1lbnQgfHwgZSkgIT09IHAgJiYgZChlKTsgdmFyIGkgPSByLmF0dHJIYW5kbGVbdC50b0xvd2VyQ2FzZSgpXSwgbyA9IGkgJiYgRC5jYWxsKHIuYXR0ckhhbmRsZSwgdC50b0xvd2VyQ2FzZSgpKSA/IGkoZSwgdCwgIWcpIDogdm9pZCAwOyByZXR1cm4gdm9pZCAwICE9PSBvID8gbyA6IG4uYXR0cmlidXRlcyB8fCAhZyA/IGUuZ2V0QXR0cmlidXRlKHQpIDogKG8gPSBlLmdldEF0dHJpYnV0ZU5vZGUodCkpICYmIG8uc3BlY2lmaWVkID8gby52YWx1ZSA6IG51bGwgfSwgb2UuZXNjYXBlID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuIChlICsgIiIpLnJlcGxhY2UodGUsIG5lKSB9LCBvZS5lcnJvciA9IGZ1bmN0aW9uIChlKSB7IHRocm93IG5ldyBFcnJvcigiU3ludGF4IGVycm9yLCB1bnJlY29nbml6ZWQgZXhwcmVzc2lvbjogIiArIGUpIH0sIG9lLnVuaXF1ZVNvcnQgPSBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgciA9IFtdLCBpID0gMCwgbyA9IDA7IGlmIChmID0gIW4uZGV0ZWN0RHVwbGljYXRlcywgYyA9ICFuLnNvcnRTdGFibGUgJiYgZS5zbGljZSgwKSwgZS5zb3J0KEEpLCBmKSB7IHdoaWxlICh0ID0gZVtvKytdKSB0ID09PSBlW29dICYmIChpID0gci5wdXNoKG8pKTsgd2hpbGUgKGktLSkgZS5zcGxpY2UocltpXSwgMSkgfSByZXR1cm4gYyA9IG51bGwsIGUgfSwgaSA9IG9lLmdldFRleHQgPSBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgbiA9ICIiLCByID0gMCwgbyA9IGUubm9kZVR5cGU7IGlmIChvKSB7IGlmICgxID09PSBvIHx8IDkgPT09IG8gfHwgMTEgPT09IG8pIHsgaWYgKCJzdHJpbmciID09IHR5cGVvZiBlLnRleHRDb250ZW50KSByZXR1cm4gZS50ZXh0Q29udGVudDsgZm9yIChlID0gZS5maXJzdENoaWxkOyBlOyBlID0gZS5uZXh0U2libGluZyluICs9IGkoZSkgfSBlbHNlIGlmICgzID09PSBvIHx8IDQgPT09IG8pIHJldHVybiBlLm5vZGVWYWx1ZSB9IGVsc2Ugd2hpbGUgKHQgPSBlW3IrK10pIG4gKz0gaSh0KTsgcmV0dXJuIG4gfSwgKHIgPSBvZS5zZWxlY3RvcnMgPSB7IGNhY2hlTGVuZ3RoOiA1MCwgY3JlYXRlUHNldWRvOiB1ZSwgbWF0Y2g6IFgsIGF0dHJIYW5kbGU6IHt9LCBmaW5kOiB7fSwgcmVsYXRpdmU6IHsgIj4iOiB7IGRpcjogInBhcmVudE5vZGUiLCBmaXJzdDogITAgfSwgIiAiOiB7IGRpcjogInBhcmVudE5vZGUiIH0sICIrIjogeyBkaXI6ICJwcmV2aW91c1NpYmxpbmciLCBmaXJzdDogITAgfSwgIn4iOiB7IGRpcjogInByZXZpb3VzU2libGluZyIgfSB9LCBwcmVGaWx0ZXI6IHsgQVRUUjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGVbMV0gPSBlWzFdLnJlcGxhY2UoWiwgZWUpLCBlWzNdID0gKGVbM10gfHwgZVs0XSB8fCBlWzVdIHx8ICIiKS5yZXBsYWNlKFosIGVlKSwgIn49IiA9PT0gZVsyXSAmJiAoZVszXSA9ICIgIiArIGVbM10gKyAiICIpLCBlLnNsaWNlKDAsIDQpIH0sIENISUxEOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZVsxXSA9IGVbMV0udG9Mb3dlckNhc2UoKSwgIm50aCIgPT09IGVbMV0uc2xpY2UoMCwgMykgPyAoZVszXSB8fCBvZS5lcnJvcihlWzBdKSwgZVs0XSA9ICsoZVs0XSA/IGVbNV0gKyAoZVs2XSB8fCAxKSA6IDIgKiAoImV2ZW4iID09PSBlWzNdIHx8ICJvZGQiID09PSBlWzNdKSksIGVbNV0gPSArKGVbN10gKyBlWzhdIHx8ICJvZGQiID09PSBlWzNdKSkgOiBlWzNdICYmIG9lLmVycm9yKGVbMF0pLCBlIH0sIFBTRVVETzogZnVuY3Rpb24gKGUpIHsgdmFyIHQsIG4gPSAhZVs2XSAmJiBlWzJdOyByZXR1cm4gWC5DSElMRC50ZXN0KGVbMF0pID8gbnVsbCA6IChlWzNdID8gZVsyXSA9IGVbNF0gfHwgZVs1XSB8fCAiIiA6IG4gJiYgVS50ZXN0KG4pICYmICh0ID0gYShuLCAhMCkpICYmICh0ID0gbi5pbmRleE9mKCIpIiwgbi5sZW5ndGggLSB0KSAtIG4ubGVuZ3RoKSAmJiAoZVswXSA9IGVbMF0uc2xpY2UoMCwgdCksIGVbMl0gPSBuLnNsaWNlKDAsIHQpKSwgZS5zbGljZSgwLCAzKSkgfSB9LCBmaWx0ZXI6IHsgVEFHOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGUucmVwbGFjZShaLCBlZSkudG9Mb3dlckNhc2UoKTsgcmV0dXJuICIqIiA9PT0gZSA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuICEwIH0gOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZS5ub2RlTmFtZSAmJiBlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IHQgfSB9LCBDTEFTUzogZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSBFW2UgKyAiICJdOyByZXR1cm4gdCB8fCAodCA9IG5ldyBSZWdFeHAoIihefCIgKyBJICsgIikiICsgZSArICIoIiArIEkgKyAifCQpIikpICYmIEUoZSwgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHQudGVzdCgic3RyaW5nIiA9PSB0eXBlb2YgZS5jbGFzc05hbWUgJiYgZS5jbGFzc05hbWUgfHwgInVuZGVmaW5lZCIgIT0gdHlwZW9mIGUuZ2V0QXR0cmlidXRlICYmIGUuZ2V0QXR0cmlidXRlKCJjbGFzcyIpIHx8ICIiKSB9KSB9LCBBVFRSOiBmdW5jdGlvbiAoZSwgdCwgbikgeyByZXR1cm4gZnVuY3Rpb24gKHIpIHsgdmFyIGkgPSBvZS5hdHRyKHIsIGUpOyByZXR1cm4gbnVsbCA9PSBpID8gIiE9IiA9PT0gdCA6ICF0IHx8IChpICs9ICIiLCAiPSIgPT09IHQgPyBpID09PSBuIDogIiE9IiA9PT0gdCA/IGkgIT09IG4gOiAiXj0iID09PSB0ID8gbiAmJiAwID09PSBpLmluZGV4T2YobikgOiAiKj0iID09PSB0ID8gbiAmJiBpLmluZGV4T2YobikgPiAtMSA6ICIkPSIgPT09IHQgPyBuICYmIGkuc2xpY2UoLW4ubGVuZ3RoKSA9PT0gbiA6ICJ+PSIgPT09IHQgPyAoIiAiICsgaS5yZXBsYWNlKFcsICIgIikgKyAiICIpLmluZGV4T2YobikgPiAtMSA6ICJ8PSIgPT09IHQgJiYgKGkgPT09IG4gfHwgaS5zbGljZSgwLCBuLmxlbmd0aCArIDEpID09PSBuICsgIi0iKSkgfSB9LCBDSElMRDogZnVuY3Rpb24gKGUsIHQsIG4sIHIsIGkpIHsgdmFyIG8gPSAibnRoIiAhPT0gZS5zbGljZSgwLCAzKSwgYSA9ICJsYXN0IiAhPT0gZS5zbGljZSgtNCksIHUgPSAib2YtdHlwZSIgPT09IHQ7IHJldHVybiAxID09PSByICYmIDAgPT09IGkgPyBmdW5jdGlvbiAoZSkgeyByZXR1cm4gISFlLnBhcmVudE5vZGUgfSA6IGZ1bmN0aW9uICh0LCBuLCBzKSB7IHZhciBsLCBjLCBmLCBkLCBwLCBoLCBnID0gbyAhPT0gYSA/ICJuZXh0U2libGluZyIgOiAicHJldmlvdXNTaWJsaW5nIiwgdiA9IHQucGFyZW50Tm9kZSwgeSA9IHUgJiYgdC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpLCBtID0gIXMgJiYgIXUsIGIgPSAhMTsgaWYgKHYpIHsgaWYgKG8pIHsgd2hpbGUgKGcpIHsgZCA9IHQ7IHdoaWxlIChkID0gZFtnXSkgaWYgKHUgPyBkLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IHkgOiAxID09PSBkLm5vZGVUeXBlKSByZXR1cm4gITE7IGggPSBnID0gIm9ubHkiID09PSBlICYmICFoICYmICJuZXh0U2libGluZyIgfSByZXR1cm4gITAgfSBpZiAoaCA9IFthID8gdi5maXJzdENoaWxkIDogdi5sYXN0Q2hpbGRdLCBhICYmIG0pIHsgYiA9IChwID0gKGwgPSAoYyA9IChmID0gKGQgPSB2KVt4XSB8fCAoZFt4XSA9IHt9KSlbZC51bmlxdWVJRF0gfHwgKGZbZC51bmlxdWVJRF0gPSB7fSkpW2VdIHx8IFtdKVswXSA9PT0gQyAmJiBsWzFdKSAmJiBsWzJdLCBkID0gcCAmJiB2LmNoaWxkTm9kZXNbcF07IHdoaWxlIChkID0gKytwICYmIGQgJiYgZFtnXSB8fCAoYiA9IHAgPSAwKSB8fCBoLnBvcCgpKSBpZiAoMSA9PT0gZC5ub2RlVHlwZSAmJiArK2IgJiYgZCA9PT0gdCkgeyBjW2VdID0gW0MsIHAsIGJdOyBicmVhayB9IH0gZWxzZSBpZiAobSAmJiAoYiA9IHAgPSAobCA9IChjID0gKGYgPSAoZCA9IHQpW3hdIHx8IChkW3hdID0ge30pKVtkLnVuaXF1ZUlEXSB8fCAoZltkLnVuaXF1ZUlEXSA9IHt9KSlbZV0gfHwgW10pWzBdID09PSBDICYmIGxbMV0pLCAhMSA9PT0gYikgd2hpbGUgKGQgPSArK3AgJiYgZCAmJiBkW2ddIHx8IChiID0gcCA9IDApIHx8IGgucG9wKCkpIGlmICgodSA/IGQubm9kZU5hbWUudG9Mb3dlckNhc2UoKSA9PT0geSA6IDEgPT09IGQubm9kZVR5cGUpICYmICsrYiAmJiAobSAmJiAoKGMgPSAoZiA9IGRbeF0gfHwgKGRbeF0gPSB7fSkpW2QudW5pcXVlSURdIHx8IChmW2QudW5pcXVlSURdID0ge30pKVtlXSA9IFtDLCBiXSksIGQgPT09IHQpKSBicmVhazsgcmV0dXJuIChiIC09IGkpID09PSByIHx8IGIgJSByID09IDAgJiYgYiAvIHIgPj0gMCB9IH0gfSwgUFNFVURPOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiwgaSA9IHIucHNldWRvc1tlXSB8fCByLnNldEZpbHRlcnNbZS50b0xvd2VyQ2FzZSgpXSB8fCBvZS5lcnJvcigidW5zdXBwb3J0ZWQgcHNldWRvOiAiICsgZSk7IHJldHVybiBpW3hdID8gaSh0KSA6IGkubGVuZ3RoID4gMSA/IChuID0gW2UsIGUsICIiLCB0XSwgci5zZXRGaWx0ZXJzLmhhc093blByb3BlcnR5KGUudG9Mb3dlckNhc2UoKSkgPyB1ZShmdW5jdGlvbiAoZSwgbikgeyB2YXIgciwgbyA9IGkoZSwgdCksIGEgPSBvLmxlbmd0aDsgd2hpbGUgKGEtLSkgZVtyID0gUChlLCBvW2FdKV0gPSAhKG5bcl0gPSBvW2FdKSB9KSA6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBpKGUsIDAsIG4pIH0pIDogaSB9IH0sIHBzZXVkb3M6IHsgbm90OiB1ZShmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IFtdLCBuID0gW10sIHIgPSB1KGUucmVwbGFjZSgkLCAiJDEiKSk7IHJldHVybiByW3hdID8gdWUoZnVuY3Rpb24gKGUsIHQsIG4sIGkpIHsgdmFyIG8sIGEgPSByKGUsIG51bGwsIGksIFtdKSwgdSA9IGUubGVuZ3RoOyB3aGlsZSAodS0tKSAobyA9IGFbdV0pICYmIChlW3VdID0gISh0W3VdID0gbykpIH0pIDogZnVuY3Rpb24gKGUsIGksIG8pIHsgcmV0dXJuIHRbMF0gPSBlLCByKHQsIG51bGwsIG8sIG4pLCB0WzBdID0gbnVsbCwgIW4ucG9wKCkgfSB9KSwgaGFzOiB1ZShmdW5jdGlvbiAoZSkgeyByZXR1cm4gZnVuY3Rpb24gKHQpIHsgcmV0dXJuIG9lKGUsIHQpLmxlbmd0aCA+IDAgfSB9KSwgY29udGFpbnM6IHVlKGZ1bmN0aW9uIChlKSB7IHJldHVybiBlID0gZS5yZXBsYWNlKFosIGVlKSwgZnVuY3Rpb24gKHQpIHsgcmV0dXJuICh0LnRleHRDb250ZW50IHx8IHQuaW5uZXJUZXh0IHx8IGkodCkpLmluZGV4T2YoZSkgPiAtMSB9IH0pLCBsYW5nOiB1ZShmdW5jdGlvbiAoZSkgeyByZXR1cm4gVi50ZXN0KGUgfHwgIiIpIHx8IG9lLmVycm9yKCJ1bnN1cHBvcnRlZCBsYW5nOiAiICsgZSksIGUgPSBlLnJlcGxhY2UoWiwgZWUpLnRvTG93ZXJDYXNlKCksIGZ1bmN0aW9uICh0KSB7IHZhciBuOyBkbyB7IGlmIChuID0gZyA/IHQubGFuZyA6IHQuZ2V0QXR0cmlidXRlKCJ4bWw6bGFuZyIpIHx8IHQuZ2V0QXR0cmlidXRlKCJsYW5nIikpIHJldHVybiAobiA9IG4udG9Mb3dlckNhc2UoKSkgPT09IGUgfHwgMCA9PT0gbi5pbmRleE9mKGUgKyAiLSIpIH0gd2hpbGUgKCh0ID0gdC5wYXJlbnROb2RlKSAmJiAxID09PSB0Lm5vZGVUeXBlKTsgcmV0dXJuICExIH0gfSksIHRhcmdldDogZnVuY3Rpb24gKHQpIHsgdmFyIG4gPSBlLmxvY2F0aW9uICYmIGUubG9jYXRpb24uaGFzaDsgcmV0dXJuIG4gJiYgbi5zbGljZSgxKSA9PT0gdC5pZCB9LCByb290OiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZSA9PT0gaCB9LCBmb2N1czogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUgPT09IHAuYWN0aXZlRWxlbWVudCAmJiAoIXAuaGFzRm9jdXMgfHwgcC5oYXNGb2N1cygpKSAmJiAhIShlLnR5cGUgfHwgZS5ocmVmIHx8IH5lLnRhYkluZGV4KSB9LCBlbmFibGVkOiBwZSghMSksIGRpc2FibGVkOiBwZSghMCksIGNoZWNrZWQ6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpOyByZXR1cm4gImlucHV0IiA9PT0gdCAmJiAhIWUuY2hlY2tlZCB8fCAib3B0aW9uIiA9PT0gdCAmJiAhIWUuc2VsZWN0ZWQgfSwgc2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBlLnBhcmVudE5vZGUgJiYgZS5wYXJlbnROb2RlLnNlbGVjdGVkSW5kZXgsICEwID09PSBlLnNlbGVjdGVkIH0sIGVtcHR5OiBmdW5jdGlvbiAoZSkgeyBmb3IgKGUgPSBlLmZpcnN0Q2hpbGQ7IGU7IGUgPSBlLm5leHRTaWJsaW5nKWlmIChlLm5vZGVUeXBlIDwgNikgcmV0dXJuICExOyByZXR1cm4gITAgfSwgcGFyZW50OiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gIXIucHNldWRvcy5lbXB0eShlKSB9LCBoZWFkZXI6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBZLnRlc3QoZS5ub2RlTmFtZSkgfSwgaW5wdXQ6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBRLnRlc3QoZS5ub2RlTmFtZSkgfSwgYnV0dG9uOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGUubm9kZU5hbWUudG9Mb3dlckNhc2UoKTsgcmV0dXJuICJpbnB1dCIgPT09IHQgJiYgImJ1dHRvbiIgPT09IGUudHlwZSB8fCAiYnV0dG9uIiA9PT0gdCB9LCB0ZXh0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdDsgcmV0dXJuICJpbnB1dCIgPT09IGUubm9kZU5hbWUudG9Mb3dlckNhc2UoKSAmJiAidGV4dCIgPT09IGUudHlwZSAmJiAobnVsbCA9PSAodCA9IGUuZ2V0QXR0cmlidXRlKCJ0eXBlIikpIHx8ICJ0ZXh0IiA9PT0gdC50b0xvd2VyQ2FzZSgpKSB9LCBmaXJzdDogaGUoZnVuY3Rpb24gKCkgeyByZXR1cm4gWzBdIH0pLCBsYXN0OiBoZShmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gW3QgLSAxXSB9KSwgZXE6IGhlKGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBbbiA8IDAgPyBuICsgdCA6IG5dIH0pLCBldmVuOiBoZShmdW5jdGlvbiAoZSwgdCkgeyBmb3IgKHZhciBuID0gMDsgbiA8IHQ7IG4gKz0gMillLnB1c2gobik7IHJldHVybiBlIH0pLCBvZGQ6IGhlKGZ1bmN0aW9uIChlLCB0KSB7IGZvciAodmFyIG4gPSAxOyBuIDwgdDsgbiArPSAyKWUucHVzaChuKTsgcmV0dXJuIGUgfSksIGx0OiBoZShmdW5jdGlvbiAoZSwgdCwgbikgeyBmb3IgKHZhciByID0gbiA8IDAgPyBuICsgdCA6IG47IC0tciA+PSAwOyllLnB1c2gocik7IHJldHVybiBlIH0pLCBndDogaGUoZnVuY3Rpb24gKGUsIHQsIG4pIHsgZm9yICh2YXIgciA9IG4gPCAwID8gbiArIHQgOiBuOyArK3IgPCB0OyllLnB1c2gocik7IHJldHVybiBlIH0pIH0gfSkucHNldWRvcy5udGggPSByLnBzZXVkb3MuZXE7IGZvciAodCBpbiB7IHJhZGlvOiAhMCwgY2hlY2tib3g6ICEwLCBmaWxlOiAhMCwgcGFzc3dvcmQ6ICEwLCBpbWFnZTogITAgfSkgci5wc2V1ZG9zW3RdID0gZmUodCk7IGZvciAodCBpbiB7IHN1Ym1pdDogITAsIHJlc2V0OiAhMCB9KSByLnBzZXVkb3NbdF0gPSBkZSh0KTsgZnVuY3Rpb24gdmUoKSB7IH0gdmUucHJvdG90eXBlID0gci5maWx0ZXJzID0gci5wc2V1ZG9zLCByLnNldEZpbHRlcnMgPSBuZXcgdmUsIGEgPSBvZS50b2tlbml6ZSA9IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCBpLCBvLCBhLCB1LCBzLCBsLCBjID0gTltlICsgIiAiXTsgaWYgKGMpIHJldHVybiB0ID8gMCA6IGMuc2xpY2UoMCk7IHUgPSBlLCBzID0gW10sIGwgPSByLnByZUZpbHRlcjsgd2hpbGUgKHUpIHsgbiAmJiAhKGkgPSBGLmV4ZWModSkpIHx8IChpICYmICh1ID0gdS5zbGljZShpWzBdLmxlbmd0aCkgfHwgdSksIHMucHVzaChvID0gW10pKSwgbiA9ICExLCAoaSA9IHouZXhlYyh1KSkgJiYgKG4gPSBpLnNoaWZ0KCksIG8ucHVzaCh7IHZhbHVlOiBuLCB0eXBlOiBpWzBdLnJlcGxhY2UoJCwgIiAiKSB9KSwgdSA9IHUuc2xpY2Uobi5sZW5ndGgpKTsgZm9yIChhIGluIHIuZmlsdGVyKSAhKGkgPSBYW2FdLmV4ZWModSkpIHx8IGxbYV0gJiYgIShpID0gbFthXShpKSkgfHwgKG4gPSBpLnNoaWZ0KCksIG8ucHVzaCh7IHZhbHVlOiBuLCB0eXBlOiBhLCBtYXRjaGVzOiBpIH0pLCB1ID0gdS5zbGljZShuLmxlbmd0aCkpOyBpZiAoIW4pIGJyZWFrIH0gcmV0dXJuIHQgPyB1Lmxlbmd0aCA6IHUgPyBvZS5lcnJvcihlKSA6IE4oZSwgcykuc2xpY2UoMCkgfTsgZnVuY3Rpb24geWUoZSkgeyBmb3IgKHZhciB0ID0gMCwgbiA9IGUubGVuZ3RoLCByID0gIiI7IHQgPCBuOyB0KyspciArPSBlW3RdLnZhbHVlOyByZXR1cm4gciB9IGZ1bmN0aW9uIG1lKGUsIHQsIG4pIHsgdmFyIHIgPSB0LmRpciwgaSA9IHQubmV4dCwgbyA9IGkgfHwgciwgYSA9IG4gJiYgInBhcmVudE5vZGUiID09PSBvLCB1ID0gVCsrOyByZXR1cm4gdC5maXJzdCA/IGZ1bmN0aW9uICh0LCBuLCBpKSB7IHdoaWxlICh0ID0gdFtyXSkgaWYgKDEgPT09IHQubm9kZVR5cGUgfHwgYSkgcmV0dXJuIGUodCwgbiwgaSk7IHJldHVybiAhMSB9IDogZnVuY3Rpb24gKHQsIG4sIHMpIHsgdmFyIGwsIGMsIGYsIGQgPSBbQywgdV07IGlmIChzKSB7IHdoaWxlICh0ID0gdFtyXSkgaWYgKCgxID09PSB0Lm5vZGVUeXBlIHx8IGEpICYmIGUodCwgbiwgcykpIHJldHVybiAhMCB9IGVsc2Ugd2hpbGUgKHQgPSB0W3JdKSBpZiAoMSA9PT0gdC5ub2RlVHlwZSB8fCBhKSBpZiAoZiA9IHRbeF0gfHwgKHRbeF0gPSB7fSksIGMgPSBmW3QudW5pcXVlSURdIHx8IChmW3QudW5pcXVlSURdID0ge30pLCBpICYmIGkgPT09IHQubm9kZU5hbWUudG9Mb3dlckNhc2UoKSkgdCA9IHRbcl0gfHwgdDsgZWxzZSB7IGlmICgobCA9IGNbb10pICYmIGxbMF0gPT09IEMgJiYgbFsxXSA9PT0gdSkgcmV0dXJuIGRbMl0gPSBsWzJdOyBpZiAoY1tvXSA9IGQsIGRbMl0gPSBlKHQsIG4sIHMpKSByZXR1cm4gITAgfSByZXR1cm4gITEgfSB9IGZ1bmN0aW9uIGJlKGUpIHsgcmV0dXJuIGUubGVuZ3RoID4gMSA/IGZ1bmN0aW9uICh0LCBuLCByKSB7IHZhciBpID0gZS5sZW5ndGg7IHdoaWxlIChpLS0pIGlmICghZVtpXSh0LCBuLCByKSkgcmV0dXJuICExOyByZXR1cm4gITAgfSA6IGVbMF0gfSBmdW5jdGlvbiB4ZShlLCB0LCBuKSB7IGZvciAodmFyIHIgPSAwLCBpID0gdC5sZW5ndGg7IHIgPCBpOyByKyspb2UoZSwgdFtyXSwgbik7IHJldHVybiBuIH0gZnVuY3Rpb24gd2UoZSwgdCwgbiwgciwgaSkgeyBmb3IgKHZhciBvLCBhID0gW10sIHUgPSAwLCBzID0gZS5sZW5ndGgsIGwgPSBudWxsICE9IHQ7IHUgPCBzOyB1KyspKG8gPSBlW3VdKSAmJiAobiAmJiAhbihvLCByLCBpKSB8fCAoYS5wdXNoKG8pLCBsICYmIHQucHVzaCh1KSkpOyByZXR1cm4gYSB9IGZ1bmN0aW9uIENlKGUsIHQsIG4sIHIsIGksIG8pIHsgcmV0dXJuIHIgJiYgIXJbeF0gJiYgKHIgPSBDZShyKSksIGkgJiYgIWlbeF0gJiYgKGkgPSBDZShpLCBvKSksIHVlKGZ1bmN0aW9uIChvLCBhLCB1LCBzKSB7IHZhciBsLCBjLCBmLCBkID0gW10sIHAgPSBbXSwgaCA9IGEubGVuZ3RoLCBnID0gbyB8fCB4ZSh0IHx8ICIqIiwgdS5ub2RlVHlwZSA/IFt1XSA6IHUsIFtdKSwgdiA9ICFlIHx8ICFvICYmIHQgPyBnIDogd2UoZywgZCwgZSwgdSwgcyksIHkgPSBuID8gaSB8fCAobyA/IGUgOiBoIHx8IHIpID8gW10gOiBhIDogdjsgaWYgKG4gJiYgbih2LCB5LCB1LCBzKSwgcikgeyBsID0gd2UoeSwgcCksIHIobCwgW10sIHUsIHMpLCBjID0gbC5sZW5ndGg7IHdoaWxlIChjLS0pIChmID0gbFtjXSkgJiYgKHlbcFtjXV0gPSAhKHZbcFtjXV0gPSBmKSkgfSBpZiAobykgeyBpZiAoaSB8fCBlKSB7IGlmIChpKSB7IGwgPSBbXSwgYyA9IHkubGVuZ3RoOyB3aGlsZSAoYy0tKSAoZiA9IHlbY10pICYmIGwucHVzaCh2W2NdID0gZik7IGkobnVsbCwgeSA9IFtdLCBsLCBzKSB9IGMgPSB5Lmxlbmd0aDsgd2hpbGUgKGMtLSkgKGYgPSB5W2NdKSAmJiAobCA9IGkgPyBQKG8sIGYpIDogZFtjXSkgPiAtMSAmJiAob1tsXSA9ICEoYVtsXSA9IGYpKSB9IH0gZWxzZSB5ID0gd2UoeSA9PT0gYSA/IHkuc3BsaWNlKGgsIHkubGVuZ3RoKSA6IHkpLCBpID8gaShudWxsLCBhLCB5LCBzKSA6IHEuYXBwbHkoYSwgeSkgfSkgfSBmdW5jdGlvbiBUZShlKSB7IGZvciAodmFyIHQsIG4sIGksIG8gPSBlLmxlbmd0aCwgYSA9IHIucmVsYXRpdmVbZVswXS50eXBlXSwgdSA9IGEgfHwgci5yZWxhdGl2ZVsiICJdLCBzID0gYSA/IDEgOiAwLCBjID0gbWUoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUgPT09IHQgfSwgdSwgITApLCBmID0gbWUoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIFAodCwgZSkgPiAtMSB9LCB1LCAhMCksIGQgPSBbZnVuY3Rpb24gKGUsIG4sIHIpIHsgdmFyIGkgPSAhYSAmJiAociB8fCBuICE9PSBsKSB8fCAoKHQgPSBuKS5ub2RlVHlwZSA/IGMoZSwgbiwgcikgOiBmKGUsIG4sIHIpKTsgcmV0dXJuIHQgPSBudWxsLCBpIH1dOyBzIDwgbzsgcysrKWlmIChuID0gci5yZWxhdGl2ZVtlW3NdLnR5cGVdKSBkID0gW21lKGJlKGQpLCBuKV07IGVsc2UgeyBpZiAoKG4gPSByLmZpbHRlcltlW3NdLnR5cGVdLmFwcGx5KG51bGwsIGVbc10ubWF0Y2hlcykpW3hdKSB7IGZvciAoaSA9ICsrczsgaSA8IG87IGkrKylpZiAoci5yZWxhdGl2ZVtlW2ldLnR5cGVdKSBicmVhazsgcmV0dXJuIENlKHMgPiAxICYmIGJlKGQpLCBzID4gMSAmJiB5ZShlLnNsaWNlKDAsIHMgLSAxKS5jb25jYXQoeyB2YWx1ZTogIiAiID09PSBlW3MgLSAyXS50eXBlID8gIioiIDogIiIgfSkpLnJlcGxhY2UoJCwgIiQxIiksIG4sIHMgPCBpICYmIFRlKGUuc2xpY2UocywgaSkpLCBpIDwgbyAmJiBUZShlID0gZS5zbGljZShpKSksIGkgPCBvICYmIHllKGUpKSB9IGQucHVzaChuKSB9IHJldHVybiBiZShkKSB9IGZ1bmN0aW9uIEVlKGUsIHQpIHsgdmFyIG4gPSB0Lmxlbmd0aCA+IDAsIGkgPSBlLmxlbmd0aCA+IDAsIG8gPSBmdW5jdGlvbiAobywgYSwgdSwgcywgYykgeyB2YXIgZiwgaCwgdiwgeSA9IDAsIG0gPSAiMCIsIGIgPSBvICYmIFtdLCB4ID0gW10sIHcgPSBsLCBUID0gbyB8fCBpICYmIHIuZmluZC5UQUcoIioiLCBjKSwgRSA9IEMgKz0gbnVsbCA9PSB3ID8gMSA6IE1hdGgucmFuZG9tKCkgfHwgLjEsIE4gPSBULmxlbmd0aDsgZm9yIChjICYmIChsID0gYSA9PT0gcCB8fCBhIHx8IGMpOyBtICE9PSBOICYmIG51bGwgIT0gKGYgPSBUW21dKTsgbSsrKSB7IGlmIChpICYmIGYpIHsgaCA9IDAsIGEgfHwgZi5vd25lckRvY3VtZW50ID09PSBwIHx8IChkKGYpLCB1ID0gIWcpOyB3aGlsZSAodiA9IGVbaCsrXSkgaWYgKHYoZiwgYSB8fCBwLCB1KSkgeyBzLnB1c2goZik7IGJyZWFrIH0gYyAmJiAoQyA9IEUpIH0gbiAmJiAoKGYgPSAhdiAmJiBmKSAmJiB5LS0gLCBvICYmIGIucHVzaChmKSkgfSBpZiAoeSArPSBtLCBuICYmIG0gIT09IHkpIHsgaCA9IDA7IHdoaWxlICh2ID0gdFtoKytdKSB2KGIsIHgsIGEsIHUpOyBpZiAobykgeyBpZiAoeSA+IDApIHdoaWxlIChtLS0pIGJbbV0gfHwgeFttXSB8fCAoeFttXSA9IEwuY2FsbChzKSk7IHggPSB3ZSh4KSB9IHEuYXBwbHkocywgeCksIGMgJiYgIW8gJiYgeC5sZW5ndGggPiAwICYmIHkgKyB0Lmxlbmd0aCA+IDEgJiYgb2UudW5pcXVlU29ydChzKSB9IHJldHVybiBjICYmIChDID0gRSwgbCA9IHcpLCBiIH07IHJldHVybiBuID8gdWUobykgOiBvIH0gcmV0dXJuIHUgPSBvZS5jb21waWxlID0gZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIgPSBbXSwgaSA9IFtdLCBvID0ga1tlICsgIiAiXTsgaWYgKCFvKSB7IHQgfHwgKHQgPSBhKGUpKSwgbiA9IHQubGVuZ3RoOyB3aGlsZSAobi0tKSAobyA9IFRlKHRbbl0pKVt4XSA/IHIucHVzaChvKSA6IGkucHVzaChvKTsgKG8gPSBrKGUsIEVlKGksIHIpKSkuc2VsZWN0b3IgPSBlIH0gcmV0dXJuIG8gfSwgcyA9IG9lLnNlbGVjdCA9IGZ1bmN0aW9uIChlLCB0LCBuLCBpKSB7IHZhciBvLCBzLCBsLCBjLCBmLCBkID0gImZ1bmN0aW9uIiA9PSB0eXBlb2YgZSAmJiBlLCBwID0gIWkgJiYgYShlID0gZC5zZWxlY3RvciB8fCBlKTsgaWYgKG4gPSBuIHx8IFtdLCAxID09PSBwLmxlbmd0aCkgeyBpZiAoKHMgPSBwWzBdID0gcFswXS5zbGljZSgwKSkubGVuZ3RoID4gMiAmJiAiSUQiID09PSAobCA9IHNbMF0pLnR5cGUgJiYgOSA9PT0gdC5ub2RlVHlwZSAmJiBnICYmIHIucmVsYXRpdmVbc1sxXS50eXBlXSkgeyBpZiAoISh0ID0gKHIuZmluZC5JRChsLm1hdGNoZXNbMF0ucmVwbGFjZShaLCBlZSksIHQpIHx8IFtdKVswXSkpIHJldHVybiBuOyBkICYmICh0ID0gdC5wYXJlbnROb2RlKSwgZSA9IGUuc2xpY2Uocy5zaGlmdCgpLnZhbHVlLmxlbmd0aCkgfSBvID0gWC5uZWVkc0NvbnRleHQudGVzdChlKSA/IDAgOiBzLmxlbmd0aDsgd2hpbGUgKG8tLSkgeyBpZiAobCA9IHNbb10sIHIucmVsYXRpdmVbYyA9IGwudHlwZV0pIGJyZWFrOyBpZiAoKGYgPSByLmZpbmRbY10pICYmIChpID0gZihsLm1hdGNoZXNbMF0ucmVwbGFjZShaLCBlZSksIEoudGVzdChzWzBdLnR5cGUpICYmIGdlKHQucGFyZW50Tm9kZSkgfHwgdCkpKSB7IGlmIChzLnNwbGljZShvLCAxKSwgIShlID0gaS5sZW5ndGggJiYgeWUocykpKSByZXR1cm4gcS5hcHBseShuLCBpKSwgbjsgYnJlYWsgfSB9IH0gcmV0dXJuIChkIHx8IHUoZSwgcCkpKGksIHQsICFnLCBuLCAhdCB8fCBKLnRlc3QoZSkgJiYgZ2UodC5wYXJlbnROb2RlKSB8fCB0KSwgbiB9LCBuLnNvcnRTdGFibGUgPSB4LnNwbGl0KCIiKS5zb3J0KEEpLmpvaW4oIiIpID09PSB4LCBuLmRldGVjdER1cGxpY2F0ZXMgPSAhIWYsIGQoKSwgbi5zb3J0RGV0YWNoZWQgPSBzZShmdW5jdGlvbiAoZSkgeyByZXR1cm4gMSAmIGUuY29tcGFyZURvY3VtZW50UG9zaXRpb24ocC5jcmVhdGVFbGVtZW50KCJmaWVsZHNldCIpKSB9KSwgc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUuaW5uZXJIVE1MID0gIjxhIGhyZWY9JyMnPjwvYT4iLCAiIyIgPT09IGUuZmlyc3RDaGlsZC5nZXRBdHRyaWJ1dGUoImhyZWYiKSB9KSB8fCBsZSgidHlwZXxocmVmfGhlaWdodHx3aWR0aCIsIGZ1bmN0aW9uIChlLCB0LCBuKSB7IGlmICghbikgcmV0dXJuIGUuZ2V0QXR0cmlidXRlKHQsICJ0eXBlIiA9PT0gdC50b0xvd2VyQ2FzZSgpID8gMSA6IDIpIH0pLCBuLmF0dHJpYnV0ZXMgJiYgc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUuaW5uZXJIVE1MID0gIjxpbnB1dC8+IiwgZS5maXJzdENoaWxkLnNldEF0dHJpYnV0ZSgidmFsdWUiLCAiIiksICIiID09PSBlLmZpcnN0Q2hpbGQuZ2V0QXR0cmlidXRlKCJ2YWx1ZSIpIH0pIHx8IGxlKCJ2YWx1ZSIsIGZ1bmN0aW9uIChlLCB0LCBuKSB7IGlmICghbiAmJiAiaW5wdXQiID09PSBlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkpIHJldHVybiBlLmRlZmF1bHRWYWx1ZSB9KSwgc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIG51bGwgPT0gZS5nZXRBdHRyaWJ1dGUoImRpc2FibGVkIikgfSkgfHwgbGUoSCwgZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHI7IGlmICghbikgcmV0dXJuICEwID09PSBlW3RdID8gdC50b0xvd2VyQ2FzZSgpIDogKHIgPSBlLmdldEF0dHJpYnV0ZU5vZGUodCkpICYmIHIuc3BlY2lmaWVkID8gci52YWx1ZSA6IG51bGwgfSksIG9lIH0oZSk7IHcuZmluZCA9IEUsIHcuZXhwciA9IEUuc2VsZWN0b3JzLCB3LmV4cHJbIjoiXSA9IHcuZXhwci5wc2V1ZG9zLCB3LnVuaXF1ZVNvcnQgPSB3LnVuaXF1ZSA9IEUudW5pcXVlU29ydCwgdy50ZXh0ID0gRS5nZXRUZXh0LCB3LmlzWE1MRG9jID0gRS5pc1hNTCwgdy5jb250YWlucyA9IEUuY29udGFpbnMsIHcuZXNjYXBlU2VsZWN0b3IgPSBFLmVzY2FwZTsgdmFyIE4gPSBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciA9IFtdLCBpID0gdm9pZCAwICE9PSBuOyB3aGlsZSAoKGUgPSBlW3RdKSAmJiA5ICE9PSBlLm5vZGVUeXBlKSBpZiAoMSA9PT0gZS5ub2RlVHlwZSkgeyBpZiAoaSAmJiB3KGUpLmlzKG4pKSBicmVhazsgci5wdXNoKGUpIH0gcmV0dXJuIHIgfSwgayA9IGZ1bmN0aW9uIChlLCB0KSB7IGZvciAodmFyIG4gPSBbXTsgZTsgZSA9IGUubmV4dFNpYmxpbmcpMSA9PT0gZS5ub2RlVHlwZSAmJiBlICE9PSB0ICYmIG4ucHVzaChlKTsgcmV0dXJuIG4gfSwgQSA9IHcuZXhwci5tYXRjaC5uZWVkc0NvbnRleHQ7IGZ1bmN0aW9uIEQoZSwgdCkgeyByZXR1cm4gZS5ub2RlTmFtZSAmJiBlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IHQudG9Mb3dlckNhc2UoKSB9IHZhciBTID0gL148KFthLXpdW15cL1wwPjpceDIwXHRcclxuXGZdKilbXHgyMFx0XHJcblxmXSpcLz8+KD86PFwvXDE+fCkkL2k7IGZ1bmN0aW9uIEwoZSwgdCwgbikgeyByZXR1cm4gZyh0KSA/IHcuZ3JlcChlLCBmdW5jdGlvbiAoZSwgcikgeyByZXR1cm4gISF0LmNhbGwoZSwgciwgZSkgIT09IG4gfSkgOiB0Lm5vZGVUeXBlID8gdy5ncmVwKGUsIGZ1bmN0aW9uIChlKSB7IHJldHVybiBlID09PSB0ICE9PSBuIH0pIDogInN0cmluZyIgIT0gdHlwZW9mIHQgPyB3LmdyZXAoZSwgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHMuY2FsbCh0LCBlKSA+IC0xICE9PSBuIH0pIDogdy5maWx0ZXIodCwgZSwgbikgfSB3LmZpbHRlciA9IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHZhciByID0gdFswXTsgcmV0dXJuIG4gJiYgKGUgPSAiOm5vdCgiICsgZSArICIpIiksIDEgPT09IHQubGVuZ3RoICYmIDEgPT09IHIubm9kZVR5cGUgPyB3LmZpbmQubWF0Y2hlc1NlbGVjdG9yKHIsIGUpID8gW3JdIDogW10gOiB3LmZpbmQubWF0Y2hlcyhlLCB3LmdyZXAodCwgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIDEgPT09IGUubm9kZVR5cGUgfSkpIH0sIHcuZm4uZXh0ZW5kKHsgZmluZDogZnVuY3Rpb24gKGUpIHsgdmFyIHQsIG4sIHIgPSB0aGlzLmxlbmd0aCwgaSA9IHRoaXM7IGlmICgic3RyaW5nIiAhPSB0eXBlb2YgZSkgcmV0dXJuIHRoaXMucHVzaFN0YWNrKHcoZSkuZmlsdGVyKGZ1bmN0aW9uICgpIHsgZm9yICh0ID0gMDsgdCA8IHI7IHQrKylpZiAody5jb250YWlucyhpW3RdLCB0aGlzKSkgcmV0dXJuICEwIH0pKTsgZm9yIChuID0gdGhpcy5wdXNoU3RhY2soW10pLCB0ID0gMDsgdCA8IHI7IHQrKyl3LmZpbmQoZSwgaVt0XSwgbik7IHJldHVybiByID4gMSA/IHcudW5pcXVlU29ydChuKSA6IG4gfSwgZmlsdGVyOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5wdXNoU3RhY2soTCh0aGlzLCBlIHx8IFtdLCAhMSkpIH0sIG5vdDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHRoaXMucHVzaFN0YWNrKEwodGhpcywgZSB8fCBbXSwgITApKSB9LCBpczogZnVuY3Rpb24gKGUpIHsgcmV0dXJuICEhTCh0aGlzLCAic3RyaW5nIiA9PSB0eXBlb2YgZSAmJiBBLnRlc3QoZSkgPyB3KGUpIDogZSB8fCBbXSwgITEpLmxlbmd0aCB9IH0pOyB2YXIgaiwgcSA9IC9eKD86XHMqKDxbXHdcV10rPilbXj5dKnwjKFtcdy1dKykpJC87ICh3LmZuLmluaXQgPSBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgaSwgbzsgaWYgKCFlKSByZXR1cm4gdGhpczsgaWYgKG4gPSBuIHx8IGosICJzdHJpbmciID09IHR5cGVvZiBlKSB7IGlmICghKGkgPSAiPCIgPT09IGVbMF0gJiYgIj4iID09PSBlW2UubGVuZ3RoIC0gMV0gJiYgZS5sZW5ndGggPj0gMyA/IFtudWxsLCBlLCBudWxsXSA6IHEuZXhlYyhlKSkgfHwgIWlbMV0gJiYgdCkgcmV0dXJuICF0IHx8IHQuanF1ZXJ5ID8gKHQgfHwgbikuZmluZChlKSA6IHRoaXMuY29uc3RydWN0b3IodCkuZmluZChlKTsgaWYgKGlbMV0pIHsgaWYgKHQgPSB0IGluc3RhbmNlb2YgdyA/IHRbMF0gOiB0LCB3Lm1lcmdlKHRoaXMsIHcucGFyc2VIVE1MKGlbMV0sIHQgJiYgdC5ub2RlVHlwZSA/IHQub3duZXJEb2N1bWVudCB8fCB0IDogciwgITApKSwgUy50ZXN0KGlbMV0pICYmIHcuaXNQbGFpbk9iamVjdCh0KSkgZm9yIChpIGluIHQpIGcodGhpc1tpXSkgPyB0aGlzW2ldKHRbaV0pIDogdGhpcy5hdHRyKGksIHRbaV0pOyByZXR1cm4gdGhpcyB9IHJldHVybiAobyA9IHIuZ2V0RWxlbWVudEJ5SWQoaVsyXSkpICYmICh0aGlzWzBdID0gbywgdGhpcy5sZW5ndGggPSAxKSwgdGhpcyB9IHJldHVybiBlLm5vZGVUeXBlID8gKHRoaXNbMF0gPSBlLCB0aGlzLmxlbmd0aCA9IDEsIHRoaXMpIDogZyhlKSA/IHZvaWQgMCAhPT0gbi5yZWFkeSA/IG4ucmVhZHkoZSkgOiBlKHcpIDogdy5tYWtlQXJyYXkoZSwgdGhpcykgfSkucHJvdG90eXBlID0gdy5mbiwgaiA9IHcocik7IHZhciBPID0gL14oPzpwYXJlbnRzfHByZXYoPzpVbnRpbHxBbGwpKS8sIFAgPSB7IGNoaWxkcmVuOiAhMCwgY29udGVudHM6ICEwLCBuZXh0OiAhMCwgcHJldjogITAgfTsgdy5mbi5leHRlbmQoeyBoYXM6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gdyhlLCB0aGlzKSwgbiA9IHQubGVuZ3RoOyByZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24gKCkgeyBmb3IgKHZhciBlID0gMDsgZSA8IG47IGUrKylpZiAody5jb250YWlucyh0aGlzLCB0W2VdKSkgcmV0dXJuICEwIH0pIH0sIGNsb3Nlc3Q6IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCByID0gMCwgaSA9IHRoaXMubGVuZ3RoLCBvID0gW10sIGEgPSAic3RyaW5nIiAhPSB0eXBlb2YgZSAmJiB3KGUpOyBpZiAoIUEudGVzdChlKSkgZm9yICg7IHIgPCBpOyByKyspZm9yIChuID0gdGhpc1tyXTsgbiAmJiBuICE9PSB0OyBuID0gbi5wYXJlbnROb2RlKWlmIChuLm5vZGVUeXBlIDwgMTEgJiYgKGEgPyBhLmluZGV4KG4pID4gLTEgOiAxID09PSBuLm5vZGVUeXBlICYmIHcuZmluZC5tYXRjaGVzU2VsZWN0b3IobiwgZSkpKSB7IG8ucHVzaChuKTsgYnJlYWsgfSByZXR1cm4gdGhpcy5wdXNoU3RhY2soby5sZW5ndGggPiAxID8gdy51bmlxdWVTb3J0KG8pIDogbykgfSwgaW5kZXg6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBlID8gInN0cmluZyIgPT0gdHlwZW9mIGUgPyBzLmNhbGwodyhlKSwgdGhpc1swXSkgOiBzLmNhbGwodGhpcywgZS5qcXVlcnkgPyBlWzBdIDogZSkgOiB0aGlzWzBdICYmIHRoaXNbMF0ucGFyZW50Tm9kZSA/IHRoaXMuZmlyc3QoKS5wcmV2QWxsKCkubGVuZ3RoIDogLTEgfSwgYWRkOiBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gdGhpcy5wdXNoU3RhY2sody51bmlxdWVTb3J0KHcubWVyZ2UodGhpcy5nZXQoKSwgdyhlLCB0KSkpKSB9LCBhZGRCYWNrOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5hZGQobnVsbCA9PSBlID8gdGhpcy5wcmV2T2JqZWN0IDogdGhpcy5wcmV2T2JqZWN0LmZpbHRlcihlKSkgfSB9KTsgZnVuY3Rpb24gSChlLCB0KSB7IHdoaWxlICgoZSA9IGVbdF0pICYmIDEgIT09IGUubm9kZVR5cGUpOyByZXR1cm4gZSB9IHcuZWFjaCh7IHBhcmVudDogZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSBlLnBhcmVudE5vZGU7IHJldHVybiB0ICYmIDExICE9PSB0Lm5vZGVUeXBlID8gdCA6IG51bGwgfSwgcGFyZW50czogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIE4oZSwgInBhcmVudE5vZGUiKSB9LCBwYXJlbnRzVW50aWw6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBOKGUsICJwYXJlbnROb2RlIiwgbikgfSwgbmV4dDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEgoZSwgIm5leHRTaWJsaW5nIikgfSwgcHJldjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEgoZSwgInByZXZpb3VzU2libGluZyIpIH0sIG5leHRBbGw6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBOKGUsICJuZXh0U2libGluZyIpIH0sIHByZXZBbGw6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBOKGUsICJwcmV2aW91c1NpYmxpbmciKSB9LCBuZXh0VW50aWw6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBOKGUsICJuZXh0U2libGluZyIsIG4pIH0sIHByZXZVbnRpbDogZnVuY3Rpb24gKGUsIHQsIG4pIHsgcmV0dXJuIE4oZSwgInByZXZpb3VzU2libGluZyIsIG4pIH0sIHNpYmxpbmdzOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gaygoZS5wYXJlbnROb2RlIHx8IHt9KS5maXJzdENoaWxkLCBlKSB9LCBjaGlsZHJlbjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGsoZS5maXJzdENoaWxkKSB9LCBjb250ZW50czogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEQoZSwgImlmcmFtZSIpID8gZS5jb250ZW50RG9jdW1lbnQgOiAoRChlLCAidGVtcGxhdGUiKSAmJiAoZSA9IGUuY29udGVudCB8fCBlKSwgdy5tZXJnZShbXSwgZS5jaGlsZE5vZGVzKSkgfSB9LCBmdW5jdGlvbiAoZSwgdCkgeyB3LmZuW2VdID0gZnVuY3Rpb24gKG4sIHIpIHsgdmFyIGkgPSB3Lm1hcCh0aGlzLCB0LCBuKTsgcmV0dXJuICJVbnRpbCIgIT09IGUuc2xpY2UoLTUpICYmIChyID0gbiksIHIgJiYgInN0cmluZyIgPT0gdHlwZW9mIHIgJiYgKGkgPSB3LmZpbHRlcihyLCBpKSksIHRoaXMubGVuZ3RoID4gMSAmJiAoUFtlXSB8fCB3LnVuaXF1ZVNvcnQoaSksIE8udGVzdChlKSAmJiBpLnJldmVyc2UoKSksIHRoaXMucHVzaFN0YWNrKGkpIH0gfSk7IHZhciBJID0gL1teXHgyMFx0XHJcblxmXSsvZzsgZnVuY3Rpb24gUihlKSB7IHZhciB0ID0ge307IHJldHVybiB3LmVhY2goZS5tYXRjaChJKSB8fCBbXSwgZnVuY3Rpb24gKGUsIG4pIHsgdFtuXSA9ICEwIH0pLCB0IH0gdy5DYWxsYmFja3MgPSBmdW5jdGlvbiAoZSkgeyBlID0gInN0cmluZyIgPT0gdHlwZW9mIGUgPyBSKGUpIDogdy5leHRlbmQoe30sIGUpOyB2YXIgdCwgbiwgciwgaSwgbyA9IFtdLCBhID0gW10sIHUgPSAtMSwgcyA9IGZ1bmN0aW9uICgpIHsgZm9yIChpID0gaSB8fCBlLm9uY2UsIHIgPSB0ID0gITA7IGEubGVuZ3RoOyB1ID0gLTEpIHsgbiA9IGEuc2hpZnQoKTsgd2hpbGUgKCsrdSA8IG8ubGVuZ3RoKSAhMSA9PT0gb1t1XS5hcHBseShuWzBdLCBuWzFdKSAmJiBlLnN0b3BPbkZhbHNlICYmICh1ID0gby5sZW5ndGgsIG4gPSAhMSkgfSBlLm1lbW9yeSB8fCAobiA9ICExKSwgdCA9ICExLCBpICYmIChvID0gbiA/IFtdIDogIiIpIH0sIGwgPSB7IGFkZDogZnVuY3Rpb24gKCkgeyByZXR1cm4gbyAmJiAobiAmJiAhdCAmJiAodSA9IG8ubGVuZ3RoIC0gMSwgYS5wdXNoKG4pKSwgZnVuY3Rpb24gdChuKSB7IHcuZWFjaChuLCBmdW5jdGlvbiAobiwgcikgeyBnKHIpID8gZS51bmlxdWUgJiYgbC5oYXMocikgfHwgby5wdXNoKHIpIDogciAmJiByLmxlbmd0aCAmJiAic3RyaW5nIiAhPT0gYihyKSAmJiB0KHIpIH0pIH0oYXJndW1lbnRzKSwgbiAmJiAhdCAmJiBzKCkpLCB0aGlzIH0sIHJlbW92ZTogZnVuY3Rpb24gKCkgeyByZXR1cm4gdy5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG47IHdoaWxlICgobiA9IHcuaW5BcnJheSh0LCBvLCBuKSkgPiAtMSkgby5zcGxpY2UobiwgMSksIG4gPD0gdSAmJiB1LS0gfSksIHRoaXMgfSwgaGFzOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZSA/IHcuaW5BcnJheShlLCBvKSA+IC0xIDogby5sZW5ndGggPiAwIH0sIGVtcHR5OiBmdW5jdGlvbiAoKSB7IHJldHVybiBvICYmIChvID0gW10pLCB0aGlzIH0sIGRpc2FibGU6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGkgPSBhID0gW10sIG8gPSBuID0gIiIsIHRoaXMgfSwgZGlzYWJsZWQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuICFvIH0sIGxvY2s6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGkgPSBhID0gW10sIG4gfHwgdCB8fCAobyA9IG4gPSAiIiksIHRoaXMgfSwgbG9ja2VkOiBmdW5jdGlvbiAoKSB7IHJldHVybiAhIWkgfSwgZmlyZVdpdGg6IGZ1bmN0aW9uIChlLCBuKSB7IHJldHVybiBpIHx8IChuID0gW2UsIChuID0gbiB8fCBbXSkuc2xpY2UgPyBuLnNsaWNlKCkgOiBuXSwgYS5wdXNoKG4pLCB0IHx8IHMoKSksIHRoaXMgfSwgZmlyZTogZnVuY3Rpb24gKCkgeyByZXR1cm4gbC5maXJlV2l0aCh0aGlzLCBhcmd1bWVudHMpLCB0aGlzIH0sIGZpcmVkOiBmdW5jdGlvbiAoKSB7IHJldHVybiAhIXIgfSB9OyByZXR1cm4gbCB9OyBmdW5jdGlvbiBCKGUpIHsgcmV0dXJuIGUgfSBmdW5jdGlvbiBNKGUpIHsgdGhyb3cgZSB9IGZ1bmN0aW9uIFcoZSwgdCwgbiwgcikgeyB2YXIgaTsgdHJ5IHsgZSAmJiBnKGkgPSBlLnByb21pc2UpID8gaS5jYWxsKGUpLmRvbmUodCkuZmFpbChuKSA6IGUgJiYgZyhpID0gZS50aGVuKSA/IGkuY2FsbChlLCB0LCBuKSA6IHQuYXBwbHkodm9pZCAwLCBbZV0uc2xpY2UocikpIH0gY2F0Y2ggKGUpIHsgbi5hcHBseSh2b2lkIDAsIFtlXSkgfSB9IHcuZXh0ZW5kKHsgRGVmZXJyZWQ6IGZ1bmN0aW9uICh0KSB7IHZhciBuID0gW1sibm90aWZ5IiwgInByb2dyZXNzIiwgdy5DYWxsYmFja3MoIm1lbW9yeSIpLCB3LkNhbGxiYWNrcygibWVtb3J5IiksIDJdLCBbInJlc29sdmUiLCAiZG9uZSIsIHcuQ2FsbGJhY2tzKCJvbmNlIG1lbW9yeSIpLCB3LkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSwgMCwgInJlc29sdmVkIl0sIFsicmVqZWN0IiwgImZhaWwiLCB3LkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSwgdy5DYWxsYmFja3MoIm9uY2UgbWVtb3J5IiksIDEsICJyZWplY3RlZCJdXSwgciA9ICJwZW5kaW5nIiwgaSA9IHsgc3RhdGU6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHIgfSwgYWx3YXlzOiBmdW5jdGlvbiAoKSB7IHJldHVybiBvLmRvbmUoYXJndW1lbnRzKS5mYWlsKGFyZ3VtZW50cyksIHRoaXMgfSwgImNhdGNoIjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGkudGhlbihudWxsLCBlKSB9LCBwaXBlOiBmdW5jdGlvbiAoKSB7IHZhciBlID0gYXJndW1lbnRzOyByZXR1cm4gdy5EZWZlcnJlZChmdW5jdGlvbiAodCkgeyB3LmVhY2gobiwgZnVuY3Rpb24gKG4sIHIpIHsgdmFyIGkgPSBnKGVbcls0XV0pICYmIGVbcls0XV07IG9bclsxXV0oZnVuY3Rpb24gKCkgeyB2YXIgZSA9IGkgJiYgaS5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyBlICYmIGcoZS5wcm9taXNlKSA/IGUucHJvbWlzZSgpLnByb2dyZXNzKHQubm90aWZ5KS5kb25lKHQucmVzb2x2ZSkuZmFpbCh0LnJlamVjdCkgOiB0W3JbMF0gKyAiV2l0aCJdKHRoaXMsIGkgPyBbZV0gOiBhcmd1bWVudHMpIH0pIH0pLCBlID0gbnVsbCB9KS5wcm9taXNlKCkgfSwgdGhlbjogZnVuY3Rpb24gKHQsIHIsIGkpIHsgdmFyIG8gPSAwOyBmdW5jdGlvbiBhKHQsIG4sIHIsIGkpIHsgcmV0dXJuIGZ1bmN0aW9uICgpIHsgdmFyIHUgPSB0aGlzLCBzID0gYXJndW1lbnRzLCBsID0gZnVuY3Rpb24gKCkgeyB2YXIgZSwgbDsgaWYgKCEodCA8IG8pKSB7IGlmICgoZSA9IHIuYXBwbHkodSwgcykpID09PSBuLnByb21pc2UoKSkgdGhyb3cgbmV3IFR5cGVFcnJvcigiVGhlbmFibGUgc2VsZi1yZXNvbHV0aW9uIik7IGwgPSBlICYmICgib2JqZWN0IiA9PSB0eXBlb2YgZSB8fCAiZnVuY3Rpb24iID09IHR5cGVvZiBlKSAmJiBlLnRoZW4sIGcobCkgPyBpID8gbC5jYWxsKGUsIGEobywgbiwgQiwgaSksIGEobywgbiwgTSwgaSkpIDogKG8rKyAsIGwuY2FsbChlLCBhKG8sIG4sIEIsIGkpLCBhKG8sIG4sIE0sIGkpLCBhKG8sIG4sIEIsIG4ubm90aWZ5V2l0aCkpKSA6IChyICE9PSBCICYmICh1ID0gdm9pZCAwLCBzID0gW2VdKSwgKGkgfHwgbi5yZXNvbHZlV2l0aCkodSwgcykpIH0gfSwgYyA9IGkgPyBsIDogZnVuY3Rpb24gKCkgeyB0cnkgeyBsKCkgfSBjYXRjaCAoZSkgeyB3LkRlZmVycmVkLmV4Y2VwdGlvbkhvb2sgJiYgdy5EZWZlcnJlZC5leGNlcHRpb25Ib29rKGUsIGMuc3RhY2tUcmFjZSksIHQgKyAxID49IG8gJiYgKHIgIT09IE0gJiYgKHUgPSB2b2lkIDAsIHMgPSBbZV0pLCBuLnJlamVjdFdpdGgodSwgcykpIH0gfTsgdCA/IGMoKSA6ICh3LkRlZmVycmVkLmdldFN0YWNrSG9vayAmJiAoYy5zdGFja1RyYWNlID0gdy5EZWZlcnJlZC5nZXRTdGFja0hvb2soKSksIGUuc2V0VGltZW91dChjKSkgfSB9IHJldHVybiB3LkRlZmVycmVkKGZ1bmN0aW9uIChlKSB7IG5bMF1bM10uYWRkKGEoMCwgZSwgZyhpKSA/IGkgOiBCLCBlLm5vdGlmeVdpdGgpKSwgblsxXVszXS5hZGQoYSgwLCBlLCBnKHQpID8gdCA6IEIpKSwgblsyXVszXS5hZGQoYSgwLCBlLCBnKHIpID8gciA6IE0pKSB9KS5wcm9taXNlKCkgfSwgcHJvbWlzZTogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIG51bGwgIT0gZSA/IHcuZXh0ZW5kKGUsIGkpIDogaSB9IH0sIG8gPSB7fTsgcmV0dXJuIHcuZWFjaChuLCBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgYSA9IHRbMl0sIHUgPSB0WzVdOyBpW3RbMV1dID0gYS5hZGQsIHUgJiYgYS5hZGQoZnVuY3Rpb24gKCkgeyByID0gdSB9LCBuWzMgLSBlXVsyXS5kaXNhYmxlLCBuWzMgLSBlXVszXS5kaXNhYmxlLCBuWzBdWzJdLmxvY2ssIG5bMF1bM10ubG9jayksIGEuYWRkKHRbM10uZmlyZSksIG9bdFswXV0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiBvW3RbMF0gKyAiV2l0aCJdKHRoaXMgPT09IG8gPyB2b2lkIDAgOiB0aGlzLCBhcmd1bWVudHMpLCB0aGlzIH0sIG9bdFswXSArICJXaXRoIl0gPSBhLmZpcmVXaXRoIH0pLCBpLnByb21pc2UobyksIHQgJiYgdC5jYWxsKG8sIG8pLCBvIH0sIHdoZW46IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gYXJndW1lbnRzLmxlbmd0aCwgbiA9IHQsIHIgPSBBcnJheShuKSwgaSA9IG8uY2FsbChhcmd1bWVudHMpLCBhID0gdy5EZWZlcnJlZCgpLCB1ID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGZ1bmN0aW9uIChuKSB7IHJbZV0gPSB0aGlzLCBpW2VdID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgPyBvLmNhbGwoYXJndW1lbnRzKSA6IG4sIC0tdCB8fCBhLnJlc29sdmVXaXRoKHIsIGkpIH0gfTsgaWYgKHQgPD0gMSAmJiAoVyhlLCBhLmRvbmUodShuKSkucmVzb2x2ZSwgYS5yZWplY3QsICF0KSwgInBlbmRpbmciID09PSBhLnN0YXRlKCkgfHwgZyhpW25dICYmIGlbbl0udGhlbikpKSByZXR1cm4gYS50aGVuKCk7IHdoaWxlIChuLS0pIFcoaVtuXSwgdShuKSwgYS5yZWplY3QpOyByZXR1cm4gYS5wcm9taXNlKCkgfSB9KTsgdmFyICQgPSAvXihFdmFsfEludGVybmFsfFJhbmdlfFJlZmVyZW5jZXxTeW50YXh8VHlwZXxVUkkpRXJyb3IkLzsgdy5EZWZlcnJlZC5leGNlcHRpb25Ib29rID0gZnVuY3Rpb24gKHQsIG4pIHsgZS5jb25zb2xlICYmIGUuY29uc29sZS53YXJuICYmIHQgJiYgJC50ZXN0KHQubmFtZSkgJiYgZS5jb25zb2xlLndhcm4oImpRdWVyeS5EZWZlcnJlZCBleGNlcHRpb246ICIgKyB0Lm1lc3NhZ2UsIHQuc3RhY2ssIG4pIH0sIHcucmVhZHlFeGNlcHRpb24gPSBmdW5jdGlvbiAodCkgeyBlLnNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyB0aHJvdyB0IH0pIH07IHZhciBGID0gdy5EZWZlcnJlZCgpOyB3LmZuLnJlYWR5ID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEYudGhlbihlKVsiY2F0Y2giXShmdW5jdGlvbiAoZSkgeyB3LnJlYWR5RXhjZXB0aW9uKGUpIH0pLCB0aGlzIH0sIHcuZXh0ZW5kKHsgaXNSZWFkeTogITEsIHJlYWR5V2FpdDogMSwgcmVhZHk6IGZ1bmN0aW9uIChlKSB7ICghMCA9PT0gZSA/IC0tdy5yZWFkeVdhaXQgOiB3LmlzUmVhZHkpIHx8ICh3LmlzUmVhZHkgPSAhMCwgITAgIT09IGUgJiYgLS13LnJlYWR5V2FpdCA+IDAgfHwgRi5yZXNvbHZlV2l0aChyLCBbd10pKSB9IH0pLCB3LnJlYWR5LnRoZW4gPSBGLnRoZW47IGZ1bmN0aW9uIHooKSB7IHIucmVtb3ZlRXZlbnRMaXN0ZW5lcigiRE9NQ29udGVudExvYWRlZCIsIHopLCBlLnJlbW92ZUV2ZW50TGlzdGVuZXIoImxvYWQiLCB6KSwgdy5yZWFkeSgpIH0gImNvbXBsZXRlIiA9PT0gci5yZWFkeVN0YXRlIHx8ICJsb2FkaW5nIiAhPT0gci5yZWFkeVN0YXRlICYmICFyLmRvY3VtZW50RWxlbWVudC5kb1Njcm9sbCA/IGUuc2V0VGltZW91dCh3LnJlYWR5KSA6IChyLmFkZEV2ZW50TGlzdGVuZXIoIkRPTUNvbnRlbnRMb2FkZWQiLCB6KSwgZS5hZGRFdmVudExpc3RlbmVyKCJsb2FkIiwgeikpOyB2YXIgXyA9IGZ1bmN0aW9uIChlLCB0LCBuLCByLCBpLCBvLCBhKSB7IHZhciB1ID0gMCwgcyA9IGUubGVuZ3RoLCBsID0gbnVsbCA9PSBuOyBpZiAoIm9iamVjdCIgPT09IGIobikpIHsgaSA9ICEwOyBmb3IgKHUgaW4gbikgXyhlLCB0LCB1LCBuW3VdLCAhMCwgbywgYSkgfSBlbHNlIGlmICh2b2lkIDAgIT09IHIgJiYgKGkgPSAhMCwgZyhyKSB8fCAoYSA9ICEwKSwgbCAmJiAoYSA/ICh0LmNhbGwoZSwgciksIHQgPSBudWxsKSA6IChsID0gdCwgdCA9IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBsLmNhbGwodyhlKSwgbikgfSkpLCB0KSkgZm9yICg7IHUgPCBzOyB1KyspdChlW3VdLCBuLCBhID8gciA6IHIuY2FsbChlW3VdLCB1LCB0KGVbdV0sIG4pKSk7IHJldHVybiBpID8gZSA6IGwgPyB0LmNhbGwoZSkgOiBzID8gdChlWzBdLCBuKSA6IG8gfSwgVSA9IC9eLW1zLS8sIFYgPSAvLShbYS16XSkvZzsgZnVuY3Rpb24gWChlLCB0KSB7IHJldHVybiB0LnRvVXBwZXJDYXNlKCkgfSBmdW5jdGlvbiBRKGUpIHsgcmV0dXJuIGUucmVwbGFjZShVLCAibXMtIikucmVwbGFjZShWLCBYKSB9IHZhciBZID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuIDEgPT09IGUubm9kZVR5cGUgfHwgOSA9PT0gZS5ub2RlVHlwZSB8fCAhK2Uubm9kZVR5cGUgfTsgZnVuY3Rpb24gRygpIHsgdGhpcy5leHBhbmRvID0gdy5leHBhbmRvICsgRy51aWQrKyB9IEcudWlkID0gMSwgRy5wcm90b3R5cGUgPSB7IGNhY2hlOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGVbdGhpcy5leHBhbmRvXTsgcmV0dXJuIHQgfHwgKHQgPSB7fSwgWShlKSAmJiAoZS5ub2RlVHlwZSA/IGVbdGhpcy5leHBhbmRvXSA9IHQgOiBPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwgdGhpcy5leHBhbmRvLCB7IHZhbHVlOiB0LCBjb25maWd1cmFibGU6ICEwIH0pKSksIHQgfSwgc2V0OiBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciwgaSA9IHRoaXMuY2FjaGUoZSk7IGlmICgic3RyaW5nIiA9PSB0eXBlb2YgdCkgaVtRKHQpXSA9IG47IGVsc2UgZm9yIChyIGluIHQpIGlbUShyKV0gPSB0W3JdOyByZXR1cm4gaSB9LCBnZXQ6IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiB2b2lkIDAgPT09IHQgPyB0aGlzLmNhY2hlKGUpIDogZVt0aGlzLmV4cGFuZG9dICYmIGVbdGhpcy5leHBhbmRvXVtRKHQpXSB9LCBhY2Nlc3M6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiB2b2lkIDAgPT09IHQgfHwgdCAmJiAic3RyaW5nIiA9PSB0eXBlb2YgdCAmJiB2b2lkIDAgPT09IG4gPyB0aGlzLmdldChlLCB0KSA6ICh0aGlzLnNldChlLCB0LCBuKSwgdm9pZCAwICE9PSBuID8gbiA6IHQpIH0sIHJlbW92ZTogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIgPSBlW3RoaXMuZXhwYW5kb107IGlmICh2b2lkIDAgIT09IHIpIHsgaWYgKHZvaWQgMCAhPT0gdCkgeyBuID0gKHQgPSBBcnJheS5pc0FycmF5KHQpID8gdC5tYXAoUSkgOiAodCA9IFEodCkpIGluIHIgPyBbdF0gOiB0Lm1hdGNoKEkpIHx8IFtdKS5sZW5ndGg7IHdoaWxlIChuLS0pIGRlbGV0ZSByW3Rbbl1dIH0gKHZvaWQgMCA9PT0gdCB8fCB3LmlzRW1wdHlPYmplY3QocikpICYmIChlLm5vZGVUeXBlID8gZVt0aGlzLmV4cGFuZG9dID0gdm9pZCAwIDogZGVsZXRlIGVbdGhpcy5leHBhbmRvXSkgfSB9LCBoYXNEYXRhOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGVbdGhpcy5leHBhbmRvXTsgcmV0dXJuIHZvaWQgMCAhPT0gdCAmJiAhdy5pc0VtcHR5T2JqZWN0KHQpIH0gfTsgdmFyIEsgPSBuZXcgRywgSiA9IG5ldyBHLCBaID0gL14oPzpce1tcd1xXXSpcfXxcW1tcd1xXXSpcXSkkLywgZWUgPSAvW0EtWl0vZzsgZnVuY3Rpb24gdGUoZSkgeyByZXR1cm4gInRydWUiID09PSBlIHx8ICJmYWxzZSIgIT09IGUgJiYgKCJudWxsIiA9PT0gZSA/IG51bGwgOiBlID09PSArZSArICIiID8gK2UgOiBaLnRlc3QoZSkgPyBKU09OLnBhcnNlKGUpIDogZSkgfSBmdW5jdGlvbiBuZShlLCB0LCBuKSB7IHZhciByOyBpZiAodm9pZCAwID09PSBuICYmIDEgPT09IGUubm9kZVR5cGUpIGlmIChyID0gImRhdGEtIiArIHQucmVwbGFjZShlZSwgIi0kJiIpLnRvTG93ZXJDYXNlKCksICJzdHJpbmciID09IHR5cGVvZiAobiA9IGUuZ2V0QXR0cmlidXRlKHIpKSkgeyB0cnkgeyBuID0gdGUobikgfSBjYXRjaCAoZSkgeyB9IEouc2V0KGUsIHQsIG4pIH0gZWxzZSBuID0gdm9pZCAwOyByZXR1cm4gbiB9IHcuZXh0ZW5kKHsgaGFzRGF0YTogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEouaGFzRGF0YShlKSB8fCBLLmhhc0RhdGEoZSkgfSwgZGF0YTogZnVuY3Rpb24gKGUsIHQsIG4pIHsgcmV0dXJuIEouYWNjZXNzKGUsIHQsIG4pIH0sIHJlbW92ZURhdGE6IGZ1bmN0aW9uIChlLCB0KSB7IEoucmVtb3ZlKGUsIHQpIH0sIF9kYXRhOiBmdW5jdGlvbiAoZSwgdCwgbikgeyByZXR1cm4gSy5hY2Nlc3MoZSwgdCwgbikgfSwgX3JlbW92ZURhdGE6IGZ1bmN0aW9uIChlLCB0KSB7IEsucmVtb3ZlKGUsIHQpIH0gfSksIHcuZm4uZXh0ZW5kKHsgZGF0YTogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIsIGksIG8gPSB0aGlzWzBdLCBhID0gbyAmJiBvLmF0dHJpYnV0ZXM7IGlmICh2b2lkIDAgPT09IGUpIHsgaWYgKHRoaXMubGVuZ3RoICYmIChpID0gSi5nZXQobyksIDEgPT09IG8ubm9kZVR5cGUgJiYgIUsuZ2V0KG8sICJoYXNEYXRhQXR0cnMiKSkpIHsgbiA9IGEubGVuZ3RoOyB3aGlsZSAobi0tKSBhW25dICYmIDAgPT09IChyID0gYVtuXS5uYW1lKS5pbmRleE9mKCJkYXRhLSIpICYmIChyID0gUShyLnNsaWNlKDUpKSwgbmUobywgciwgaVtyXSkpOyBLLnNldChvLCAiaGFzRGF0YUF0dHJzIiwgITApIH0gcmV0dXJuIGkgfSByZXR1cm4gIm9iamVjdCIgPT0gdHlwZW9mIGUgPyB0aGlzLmVhY2goZnVuY3Rpb24gKCkgeyBKLnNldCh0aGlzLCBlKSB9KSA6IF8odGhpcywgZnVuY3Rpb24gKHQpIHsgdmFyIG47IGlmIChvICYmIHZvaWQgMCA9PT0gdCkgeyBpZiAodm9pZCAwICE9PSAobiA9IEouZ2V0KG8sIGUpKSkgcmV0dXJuIG47IGlmICh2b2lkIDAgIT09IChuID0gbmUobywgZSkpKSByZXR1cm4gbiB9IGVsc2UgdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgSi5zZXQodGhpcywgZSwgdCkgfSkgfSwgbnVsbCwgdCwgYXJndW1lbnRzLmxlbmd0aCA+IDEsIG51bGwsICEwKSB9LCByZW1vdmVEYXRhOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgSi5yZW1vdmUodGhpcywgZSkgfSkgfSB9KSwgdy5leHRlbmQoeyBxdWV1ZTogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHI7IGlmIChlKSByZXR1cm4gdCA9ICh0IHx8ICJmeCIpICsgInF1ZXVlIiwgciA9IEsuZ2V0KGUsIHQpLCBuICYmICghciB8fCBBcnJheS5pc0FycmF5KG4pID8gciA9IEsuYWNjZXNzKGUsIHQsIHcubWFrZUFycmF5KG4pKSA6IHIucHVzaChuKSksIHIgfHwgW10gfSwgZGVxdWV1ZTogZnVuY3Rpb24gKGUsIHQpIHsgdCA9IHQgfHwgImZ4IjsgdmFyIG4gPSB3LnF1ZXVlKGUsIHQpLCByID0gbi5sZW5ndGgsIGkgPSBuLnNoaWZ0KCksIG8gPSB3Ll9xdWV1ZUhvb2tzKGUsIHQpLCBhID0gZnVuY3Rpb24gKCkgeyB3LmRlcXVldWUoZSwgdCkgfTsgImlucHJvZ3Jlc3MiID09PSBpICYmIChpID0gbi5zaGlmdCgpLCByLS0pLCBpICYmICgiZngiID09PSB0ICYmIG4udW5zaGlmdCgiaW5wcm9ncmVzcyIpLCBkZWxldGUgby5zdG9wLCBpLmNhbGwoZSwgYSwgbykpLCAhciAmJiBvICYmIG8uZW1wdHkuZmlyZSgpIH0sIF9xdWV1ZUhvb2tzOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IHQgKyAicXVldWVIb29rcyI7IHJldHVybiBLLmdldChlLCBuKSB8fCBLLmFjY2VzcyhlLCBuLCB7IGVtcHR5OiB3LkNhbGxiYWNrcygib25jZSBtZW1vcnkiKS5hZGQoZnVuY3Rpb24gKCkgeyBLLnJlbW92ZShlLCBbdCArICJxdWV1ZSIsIG5dKSB9KSB9KSB9IH0pLCB3LmZuLmV4dGVuZCh7IHF1ZXVlOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IDI7IHJldHVybiAic3RyaW5nIiAhPSB0eXBlb2YgZSAmJiAodCA9IGUsIGUgPSAiZngiLCBuLS0pLCBhcmd1bWVudHMubGVuZ3RoIDwgbiA/IHcucXVldWUodGhpc1swXSwgZSkgOiB2b2lkIDAgPT09IHQgPyB0aGlzIDogdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgdmFyIG4gPSB3LnF1ZXVlKHRoaXMsIGUsIHQpOyB3Ll9xdWV1ZUhvb2tzKHRoaXMsIGUpLCAiZngiID09PSBlICYmICJpbnByb2dyZXNzIiAhPT0gblswXSAmJiB3LmRlcXVldWUodGhpcywgZSkgfSkgfSwgZGVxdWV1ZTogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7IHcuZGVxdWV1ZSh0aGlzLCBlKSB9KSB9LCBjbGVhclF1ZXVlOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5xdWV1ZShlIHx8ICJmeCIsIFtdKSB9LCBwcm9taXNlOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiwgciA9IDEsIGkgPSB3LkRlZmVycmVkKCksIG8gPSB0aGlzLCBhID0gdGhpcy5sZW5ndGgsIHUgPSBmdW5jdGlvbiAoKSB7IC0tciB8fCBpLnJlc29sdmVXaXRoKG8sIFtvXSkgfTsgInN0cmluZyIgIT0gdHlwZW9mIGUgJiYgKHQgPSBlLCBlID0gdm9pZCAwKSwgZSA9IGUgfHwgImZ4Ijsgd2hpbGUgKGEtLSkgKG4gPSBLLmdldChvW2FdLCBlICsgInF1ZXVlSG9va3MiKSkgJiYgbi5lbXB0eSAmJiAocisrICwgbi5lbXB0eS5hZGQodSkpOyByZXR1cm4gdSgpLCBpLnByb21pc2UodCkgfSB9KTsgdmFyIHJlID0gL1srLV0/KD86XGQqXC58KVxkKyg/OltlRV1bKy1dP1xkK3wpLy5zb3VyY2UsIGllID0gbmV3IFJlZ0V4cCgiXig/OihbKy1dKT18KSgiICsgcmUgKyAiKShbYS16JV0qKSQiLCAiaSIpLCBvZSA9IFsiVG9wIiwgIlJpZ2h0IiwgIkJvdHRvbSIsICJMZWZ0Il0sIGFlID0gZnVuY3Rpb24gKGUsIHQpIHsgcmV0dXJuICJub25lIiA9PT0gKGUgPSB0IHx8IGUpLnN0eWxlLmRpc3BsYXkgfHwgIiIgPT09IGUuc3R5bGUuZGlzcGxheSAmJiB3LmNvbnRhaW5zKGUub3duZXJEb2N1bWVudCwgZSkgJiYgIm5vbmUiID09PSB3LmNzcyhlLCAiZGlzcGxheSIpIH0sIHVlID0gZnVuY3Rpb24gKGUsIHQsIG4sIHIpIHsgdmFyIGksIG8sIGEgPSB7fTsgZm9yIChvIGluIHQpIGFbb10gPSBlLnN0eWxlW29dLCBlLnN0eWxlW29dID0gdFtvXTsgaSA9IG4uYXBwbHkoZSwgciB8fCBbXSk7IGZvciAobyBpbiB0KSBlLnN0eWxlW29dID0gYVtvXTsgcmV0dXJuIGkgfTsgZnVuY3Rpb24gc2UoZSwgdCwgbiwgcikgeyB2YXIgaSwgbywgYSA9IDIwLCB1ID0gciA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHIuY3VyKCkgfSA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHcuY3NzKGUsIHQsICIiKSB9LCBzID0gdSgpLCBsID0gbiAmJiBuWzNdIHx8ICh3LmNzc051bWJlclt0XSA/ICIiIDogInB4IiksIGMgPSAody5jc3NOdW1iZXJbdF0gfHwgInB4IiAhPT0gbCAmJiArcykgJiYgaWUuZXhlYyh3LmNzcyhlLCB0KSk7IGlmIChjICYmIGNbM10gIT09IGwpIHsgcyAvPSAyLCBsID0gbCB8fCBjWzNdLCBjID0gK3MgfHwgMTsgd2hpbGUgKGEtLSkgdy5zdHlsZShlLCB0LCBjICsgbCksICgxIC0gbykgKiAoMSAtIChvID0gdSgpIC8gcyB8fCAuNSkpIDw9IDAgJiYgKGEgPSAwKSwgYyAvPSBvOyBjICo9IDIsIHcuc3R5bGUoZSwgdCwgYyArIGwpLCBuID0gbiB8fCBbXSB9IHJldHVybiBuICYmIChjID0gK2MgfHwgK3MgfHwgMCwgaSA9IG5bMV0gPyBjICsgKG5bMV0gKyAxKSAqIG5bMl0gOiArblsyXSwgciAmJiAoci51bml0ID0gbCwgci5zdGFydCA9IGMsIHIuZW5kID0gaSkpLCBpIH0gdmFyIGxlID0ge307IGZ1bmN0aW9uIGNlKGUpIHsgdmFyIHQsIG4gPSBlLm93bmVyRG9jdW1lbnQsIHIgPSBlLm5vZGVOYW1lLCBpID0gbGVbcl07IHJldHVybiBpIHx8ICh0ID0gbi5ib2R5LmFwcGVuZENoaWxkKG4uY3JlYXRlRWxlbWVudChyKSksIGkgPSB3LmNzcyh0LCAiZGlzcGxheSIpLCB0LnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodCksICJub25lIiA9PT0gaSAmJiAoaSA9ICJibG9jayIpLCBsZVtyXSA9IGksIGkpIH0gZnVuY3Rpb24gZmUoZSwgdCkgeyBmb3IgKHZhciBuLCByLCBpID0gW10sIG8gPSAwLCBhID0gZS5sZW5ndGg7IG8gPCBhOyBvKyspKHIgPSBlW29dKS5zdHlsZSAmJiAobiA9IHIuc3R5bGUuZGlzcGxheSwgdCA/ICgibm9uZSIgPT09IG4gJiYgKGlbb10gPSBLLmdldChyLCAiZGlzcGxheSIpIHx8IG51bGwsIGlbb10gfHwgKHIuc3R5bGUuZGlzcGxheSA9ICIiKSksICIiID09PSByLnN0eWxlLmRpc3BsYXkgJiYgYWUocikgJiYgKGlbb10gPSBjZShyKSkpIDogIm5vbmUiICE9PSBuICYmIChpW29dID0gIm5vbmUiLCBLLnNldChyLCAiZGlzcGxheSIsIG4pKSk7IGZvciAobyA9IDA7IG8gPCBhOyBvKyspbnVsbCAhPSBpW29dICYmIChlW29dLnN0eWxlLmRpc3BsYXkgPSBpW29dKTsgcmV0dXJuIGUgfSB3LmZuLmV4dGVuZCh7IHNob3c6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGZlKHRoaXMsICEwKSB9LCBoaWRlOiBmdW5jdGlvbiAoKSB7IHJldHVybiBmZSh0aGlzKSB9LCB0b2dnbGU6IGZ1bmN0aW9uIChlKSB7IHJldHVybiAiYm9vbGVhbiIgPT0gdHlwZW9mIGUgPyBlID8gdGhpcy5zaG93KCkgOiB0aGlzLmhpZGUoKSA6IHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7IGFlKHRoaXMpID8gdyh0aGlzKS5zaG93KCkgOiB3KHRoaXMpLmhpZGUoKSB9KSB9IH0pOyB2YXIgZGUgPSAvXig/OmNoZWNrYm94fHJhZGlvKSQvaSwgcGUgPSAvPChbYS16XVteXC9cMD5ceDIwXHRcclxuXGZdKykvaSwgaGUgPSAvXiR8Xm1vZHVsZSR8XC8oPzpqYXZhfGVjbWEpc2NyaXB0L2ksIGdlID0geyBvcHRpb246IFsxLCAiPHNlbGVjdCBtdWx0aXBsZT0nbXVsdGlwbGUnPiIsICI8L3NlbGVjdD4iXSwgdGhlYWQ6IFsxLCAiPHRhYmxlPiIsICI8L3RhYmxlPiJdLCBjb2w6IFsyLCAiPHRhYmxlPjxjb2xncm91cD4iLCAiPC9jb2xncm91cD48L3RhYmxlPiJdLCB0cjogWzIsICI8dGFibGU+PHRib2R5PiIsICI8L3Rib2R5PjwvdGFibGU+Il0sIHRkOiBbMywgIjx0YWJsZT48dGJvZHk+PHRyPiIsICI8L3RyPjwvdGJvZHk+PC90YWJsZT4iXSwgX2RlZmF1bHQ6IFswLCAiIiwgIiJdIH07IGdlLm9wdGdyb3VwID0gZ2Uub3B0aW9uLCBnZS50Ym9keSA9IGdlLnRmb290ID0gZ2UuY29sZ3JvdXAgPSBnZS5jYXB0aW9uID0gZ2UudGhlYWQsIGdlLnRoID0gZ2UudGQ7IGZ1bmN0aW9uIHZlKGUsIHQpIHsgdmFyIG47IHJldHVybiBuID0gInVuZGVmaW5lZCIgIT0gdHlwZW9mIGUuZ2V0RWxlbWVudHNCeVRhZ05hbWUgPyBlLmdldEVsZW1lbnRzQnlUYWdOYW1lKHQgfHwgIioiKSA6ICJ1bmRlZmluZWQiICE9IHR5cGVvZiBlLnF1ZXJ5U2VsZWN0b3JBbGwgPyBlLnF1ZXJ5U2VsZWN0b3JBbGwodCB8fCAiKiIpIDogW10sIHZvaWQgMCA9PT0gdCB8fCB0ICYmIEQoZSwgdCkgPyB3Lm1lcmdlKFtlXSwgbikgOiBuIH0gZnVuY3Rpb24geWUoZSwgdCkgeyBmb3IgKHZhciBuID0gMCwgciA9IGUubGVuZ3RoOyBuIDwgcjsgbisrKUsuc2V0KGVbbl0sICJnbG9iYWxFdmFsIiwgIXQgfHwgSy5nZXQodFtuXSwgImdsb2JhbEV2YWwiKSkgfSB2YXIgbWUgPSAvPHwmIz9cdys7LzsgZnVuY3Rpb24gYmUoZSwgdCwgbiwgciwgaSkgeyBmb3IgKHZhciBvLCBhLCB1LCBzLCBsLCBjLCBmID0gdC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCksIGQgPSBbXSwgcCA9IDAsIGggPSBlLmxlbmd0aDsgcCA8IGg7IHArKylpZiAoKG8gPSBlW3BdKSB8fCAwID09PSBvKSBpZiAoIm9iamVjdCIgPT09IGIobykpIHcubWVyZ2UoZCwgby5ub2RlVHlwZSA/IFtvXSA6IG8pOyBlbHNlIGlmIChtZS50ZXN0KG8pKSB7IGEgPSBhIHx8IGYuYXBwZW5kQ2hpbGQodC5jcmVhdGVFbGVtZW50KCJkaXYiKSksIHUgPSAocGUuZXhlYyhvKSB8fCBbIiIsICIiXSlbMV0udG9Mb3dlckNhc2UoKSwgcyA9IGdlW3VdIHx8IGdlLl9kZWZhdWx0LCBhLmlubmVySFRNTCA9IHNbMV0gKyB3Lmh0bWxQcmVmaWx0ZXIobykgKyBzWzJdLCBjID0gc1swXTsgd2hpbGUgKGMtLSkgYSA9IGEubGFzdENoaWxkOyB3Lm1lcmdlKGQsIGEuY2hpbGROb2RlcyksIChhID0gZi5maXJzdENoaWxkKS50ZXh0Q29udGVudCA9ICIiIH0gZWxzZSBkLnB1c2godC5jcmVhdGVUZXh0Tm9kZShvKSk7IGYudGV4dENvbnRlbnQgPSAiIiwgcCA9IDA7IHdoaWxlIChvID0gZFtwKytdKSBpZiAociAmJiB3LmluQXJyYXkobywgcikgPiAtMSkgaSAmJiBpLnB1c2gobyk7IGVsc2UgaWYgKGwgPSB3LmNvbnRhaW5zKG8ub3duZXJEb2N1bWVudCwgbyksIGEgPSB2ZShmLmFwcGVuZENoaWxkKG8pLCAic2NyaXB0IiksIGwgJiYgeWUoYSksIG4pIHsgYyA9IDA7IHdoaWxlIChvID0gYVtjKytdKSBoZS50ZXN0KG8udHlwZSB8fCAiIikgJiYgbi5wdXNoKG8pIH0gcmV0dXJuIGYgfSAhZnVuY3Rpb24gKCkgeyB2YXIgZSA9IHIuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLmFwcGVuZENoaWxkKHIuY3JlYXRlRWxlbWVudCgiZGl2IikpLCB0ID0gci5jcmVhdGVFbGVtZW50KCJpbnB1dCIpOyB0LnNldEF0dHJpYnV0ZSgidHlwZSIsICJyYWRpbyIpLCB0LnNldEF0dHJpYnV0ZSgiY2hlY2tlZCIsICJjaGVja2VkIiksIHQuc2V0QXR0cmlidXRlKCJuYW1lIiwgInQiKSwgZS5hcHBlbmRDaGlsZCh0KSwgaC5jaGVja0Nsb25lID0gZS5jbG9uZU5vZGUoITApLmNsb25lTm9kZSghMCkubGFzdENoaWxkLmNoZWNrZWQsIGUuaW5uZXJIVE1MID0gIjx0ZXh0YXJlYT54PC90ZXh0YXJlYT4iLCBoLm5vQ2xvbmVDaGVja2VkID0gISFlLmNsb25lTm9kZSghMCkubGFzdENoaWxkLmRlZmF1bHRWYWx1ZSB9KCk7IHZhciB4ZSA9IHIuZG9jdW1lbnRFbGVtZW50LCB3ZSA9IC9ea2V5LywgQ2UgPSAvXig/Om1vdXNlfHBvaW50ZXJ8Y29udGV4dG1lbnV8ZHJhZ3xkcm9wKXxjbGljay8sIFRlID0gL14oW14uXSopKD86XC4oLispfCkvOyBmdW5jdGlvbiBFZSgpIHsgcmV0dXJuICEwIH0gZnVuY3Rpb24gTmUoKSB7IHJldHVybiAhMSB9IGZ1bmN0aW9uIGtlKCkgeyB0cnkgeyByZXR1cm4gci5hY3RpdmVFbGVtZW50IH0gY2F0Y2ggKGUpIHsgfSB9IGZ1bmN0aW9uIEFlKGUsIHQsIG4sIHIsIGksIG8pIHsgdmFyIGEsIHU7IGlmICgib2JqZWN0IiA9PSB0eXBlb2YgdCkgeyAic3RyaW5nIiAhPSB0eXBlb2YgbiAmJiAociA9IHIgfHwgbiwgbiA9IHZvaWQgMCk7IGZvciAodSBpbiB0KSBBZShlLCB1LCBuLCByLCB0W3VdLCBvKTsgcmV0dXJuIGUgfSBpZiAobnVsbCA9PSByICYmIG51bGwgPT0gaSA/IChpID0gbiwgciA9IG4gPSB2b2lkIDApIDogbnVsbCA9PSBpICYmICgic3RyaW5nIiA9PSB0eXBlb2YgbiA/IChpID0gciwgciA9IHZvaWQgMCkgOiAoaSA9IHIsIHIgPSBuLCBuID0gdm9pZCAwKSksICExID09PSBpKSBpID0gTmU7IGVsc2UgaWYgKCFpKSByZXR1cm4gZTsgcmV0dXJuIDEgPT09IG8gJiYgKGEgPSBpLCAoaSA9IGZ1bmN0aW9uIChlKSB7IHJldHVybiB3KCkub2ZmKGUpLCBhLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykgfSkuZ3VpZCA9IGEuZ3VpZCB8fCAoYS5ndWlkID0gdy5ndWlkKyspKSwgZS5lYWNoKGZ1bmN0aW9uICgpIHsgdy5ldmVudC5hZGQodGhpcywgdCwgaSwgciwgbikgfSkgfSB3LmV2ZW50ID0geyBnbG9iYWw6IHt9LCBhZGQ6IGZ1bmN0aW9uIChlLCB0LCBuLCByLCBpKSB7IHZhciBvLCBhLCB1LCBzLCBsLCBjLCBmLCBkLCBwLCBoLCBnLCB2ID0gSy5nZXQoZSk7IGlmICh2KSB7IG4uaGFuZGxlciAmJiAobiA9IChvID0gbikuaGFuZGxlciwgaSA9IG8uc2VsZWN0b3IpLCBpICYmIHcuZmluZC5tYXRjaGVzU2VsZWN0b3IoeGUsIGkpLCBuLmd1aWQgfHwgKG4uZ3VpZCA9IHcuZ3VpZCsrKSwgKHMgPSB2LmV2ZW50cykgfHwgKHMgPSB2LmV2ZW50cyA9IHt9KSwgKGEgPSB2LmhhbmRsZSkgfHwgKGEgPSB2LmhhbmRsZSA9IGZ1bmN0aW9uICh0KSB7IHJldHVybiAidW5kZWZpbmVkIiAhPSB0eXBlb2YgdyAmJiB3LmV2ZW50LnRyaWdnZXJlZCAhPT0gdC50eXBlID8gdy5ldmVudC5kaXNwYXRjaC5hcHBseShlLCBhcmd1bWVudHMpIDogdm9pZCAwIH0pLCBsID0gKHQgPSAodCB8fCAiIikubWF0Y2goSSkgfHwgWyIiXSkubGVuZ3RoOyB3aGlsZSAobC0tKSBwID0gZyA9ICh1ID0gVGUuZXhlYyh0W2xdKSB8fCBbXSlbMV0sIGggPSAodVsyXSB8fCAiIikuc3BsaXQoIi4iKS5zb3J0KCksIHAgJiYgKGYgPSB3LmV2ZW50LnNwZWNpYWxbcF0gfHwge30sIHAgPSAoaSA/IGYuZGVsZWdhdGVUeXBlIDogZi5iaW5kVHlwZSkgfHwgcCwgZiA9IHcuZXZlbnQuc3BlY2lhbFtwXSB8fCB7fSwgYyA9IHcuZXh0ZW5kKHsgdHlwZTogcCwgb3JpZ1R5cGU6IGcsIGRhdGE6IHIsIGhhbmRsZXI6IG4sIGd1aWQ6IG4uZ3VpZCwgc2VsZWN0b3I6IGksIG5lZWRzQ29udGV4dDogaSAmJiB3LmV4cHIubWF0Y2gubmVlZHNDb250ZXh0LnRlc3QoaSksIG5hbWVzcGFjZTogaC5qb2luKCIuIikgfSwgbyksIChkID0gc1twXSkgfHwgKChkID0gc1twXSA9IFtdKS5kZWxlZ2F0ZUNvdW50ID0gMCwgZi5zZXR1cCAmJiAhMSAhPT0gZi5zZXR1cC5jYWxsKGUsIHIsIGgsIGEpIHx8IGUuYWRkRXZlbnRMaXN0ZW5lciAmJiBlLmFkZEV2ZW50TGlzdGVuZXIocCwgYSkpLCBmLmFkZCAmJiAoZi5hZGQuY2FsbChlLCBjKSwgYy5oYW5kbGVyLmd1aWQgfHwgKGMuaGFuZGxlci5ndWlkID0gbi5ndWlkKSksIGkgPyBkLnNwbGljZShkLmRlbGVnYXRlQ291bnQrKywgMCwgYykgOiBkLnB1c2goYyksIHcuZXZlbnQuZ2xvYmFsW3BdID0gITApIH0gfSwgcmVtb3ZlOiBmdW5jdGlvbiAoZSwgdCwgbiwgciwgaSkgeyB2YXIgbywgYSwgdSwgcywgbCwgYywgZiwgZCwgcCwgaCwgZywgdiA9IEsuaGFzRGF0YShlKSAmJiBLLmdldChlKTsgaWYgKHYgJiYgKHMgPSB2LmV2ZW50cykpIHsgbCA9ICh0ID0gKHQgfHwgIiIpLm1hdGNoKEkpIHx8IFsiIl0pLmxlbmd0aDsgd2hpbGUgKGwtLSkgaWYgKHUgPSBUZS5leGVjKHRbbF0pIHx8IFtdLCBwID0gZyA9IHVbMV0sIGggPSAodVsyXSB8fCAiIikuc3BsaXQoIi4iKS5zb3J0KCksIHApIHsgZiA9IHcuZXZlbnQuc3BlY2lhbFtwXSB8fCB7fSwgZCA9IHNbcCA9IChyID8gZi5kZWxlZ2F0ZVR5cGUgOiBmLmJpbmRUeXBlKSB8fCBwXSB8fCBbXSwgdSA9IHVbMl0gJiYgbmV3IFJlZ0V4cCgiKF58XFwuKSIgKyBoLmpvaW4oIlxcLig/Oi4qXFwufCkiKSArICIoXFwufCQpIiksIGEgPSBvID0gZC5sZW5ndGg7IHdoaWxlIChvLS0pIGMgPSBkW29dLCAhaSAmJiBnICE9PSBjLm9yaWdUeXBlIHx8IG4gJiYgbi5ndWlkICE9PSBjLmd1aWQgfHwgdSAmJiAhdS50ZXN0KGMubmFtZXNwYWNlKSB8fCByICYmIHIgIT09IGMuc2VsZWN0b3IgJiYgKCIqKiIgIT09IHIgfHwgIWMuc2VsZWN0b3IpIHx8IChkLnNwbGljZShvLCAxKSwgYy5zZWxlY3RvciAmJiBkLmRlbGVnYXRlQ291bnQtLSAsIGYucmVtb3ZlICYmIGYucmVtb3ZlLmNhbGwoZSwgYykpOyBhICYmICFkLmxlbmd0aCAmJiAoZi50ZWFyZG93biAmJiAhMSAhPT0gZi50ZWFyZG93bi5jYWxsKGUsIGgsIHYuaGFuZGxlKSB8fCB3LnJlbW92ZUV2ZW50KGUsIHAsIHYuaGFuZGxlKSwgZGVsZXRlIHNbcF0pIH0gZWxzZSBmb3IgKHAgaW4gcykgdy5ldmVudC5yZW1vdmUoZSwgcCArIHRbbF0sIG4sIHIsICEwKTsgdy5pc0VtcHR5T2JqZWN0KHMpICYmIEsucmVtb3ZlKGUsICJoYW5kbGUgZXZlbnRzIikgfSB9LCBkaXNwYXRjaDogZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSB3LmV2ZW50LmZpeChlKSwgbiwgciwgaSwgbywgYSwgdSwgcyA9IG5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoKSwgbCA9IChLLmdldCh0aGlzLCAiZXZlbnRzIikgfHwge30pW3QudHlwZV0gfHwgW10sIGMgPSB3LmV2ZW50LnNwZWNpYWxbdC50eXBlXSB8fCB7fTsgZm9yIChzWzBdID0gdCwgbiA9IDE7IG4gPCBhcmd1bWVudHMubGVuZ3RoOyBuKyspc1tuXSA9IGFyZ3VtZW50c1tuXTsgaWYgKHQuZGVsZWdhdGVUYXJnZXQgPSB0aGlzLCAhYy5wcmVEaXNwYXRjaCB8fCAhMSAhPT0gYy5wcmVEaXNwYXRjaC5jYWxsKHRoaXMsIHQpKSB7IHUgPSB3LmV2ZW50LmhhbmRsZXJzLmNhbGwodGhpcywgdCwgbCksIG4gPSAwOyB3aGlsZSAoKG8gPSB1W24rK10pICYmICF0LmlzUHJvcGFnYXRpb25TdG9wcGVkKCkpIHsgdC5jdXJyZW50VGFyZ2V0ID0gby5lbGVtLCByID0gMDsgd2hpbGUgKChhID0gby5oYW5kbGVyc1tyKytdKSAmJiAhdC5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCgpKSB0LnJuYW1lc3BhY2UgJiYgIXQucm5hbWVzcGFjZS50ZXN0KGEubmFtZXNwYWNlKSB8fCAodC5oYW5kbGVPYmogPSBhLCB0LmRhdGEgPSBhLmRhdGEsIHZvaWQgMCAhPT0gKGkgPSAoKHcuZXZlbnQuc3BlY2lhbFthLm9yaWdUeXBlXSB8fCB7fSkuaGFuZGxlIHx8IGEuaGFuZGxlcikuYXBwbHkoby5lbGVtLCBzKSkgJiYgITEgPT09ICh0LnJlc3VsdCA9IGkpICYmICh0LnByZXZlbnREZWZhdWx0KCksIHQuc3RvcFByb3BhZ2F0aW9uKCkpKSB9IHJldHVybiBjLnBvc3REaXNwYXRjaCAmJiBjLnBvc3REaXNwYXRjaC5jYWxsKHRoaXMsIHQpLCB0LnJlc3VsdCB9IH0sIGhhbmRsZXJzOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiwgciwgaSwgbywgYSwgdSA9IFtdLCBzID0gdC5kZWxlZ2F0ZUNvdW50LCBsID0gZS50YXJnZXQ7IGlmIChzICYmIGwubm9kZVR5cGUgJiYgISgiY2xpY2siID09PSBlLnR5cGUgJiYgZS5idXR0b24gPj0gMSkpIGZvciAoOyBsICE9PSB0aGlzOyBsID0gbC5wYXJlbnROb2RlIHx8IHRoaXMpaWYgKDEgPT09IGwubm9kZVR5cGUgJiYgKCJjbGljayIgIT09IGUudHlwZSB8fCAhMCAhPT0gbC5kaXNhYmxlZCkpIHsgZm9yIChvID0gW10sIGEgPSB7fSwgbiA9IDA7IG4gPCBzOyBuKyspdm9pZCAwID09PSBhW2kgPSAociA9IHRbbl0pLnNlbGVjdG9yICsgIiAiXSAmJiAoYVtpXSA9IHIubmVlZHNDb250ZXh0ID8gdyhpLCB0aGlzKS5pbmRleChsKSA+IC0xIDogdy5maW5kKGksIHRoaXMsIG51bGwsIFtsXSkubGVuZ3RoKSwgYVtpXSAmJiBvLnB1c2gocik7IG8ubGVuZ3RoICYmIHUucHVzaCh7IGVsZW06IGwsIGhhbmRsZXJzOiBvIH0pIH0gcmV0dXJuIGwgPSB0aGlzLCBzIDwgdC5sZW5ndGggJiYgdS5wdXNoKHsgZWxlbTogbCwgaGFuZGxlcnM6IHQuc2xpY2UocykgfSksIHUgfSwgYWRkUHJvcDogZnVuY3Rpb24gKGUsIHQpIHsgT2JqZWN0LmRlZmluZVByb3BlcnR5KHcuRXZlbnQucHJvdG90eXBlLCBlLCB7IGVudW1lcmFibGU6ICEwLCBjb25maWd1cmFibGU6ICEwLCBnZXQ6IGcodCkgPyBmdW5jdGlvbiAoKSB7IGlmICh0aGlzLm9yaWdpbmFsRXZlbnQpIHJldHVybiB0KHRoaXMub3JpZ2luYWxFdmVudCkgfSA6IGZ1bmN0aW9uICgpIHsgaWYgKHRoaXMub3JpZ2luYWxFdmVudCkgcmV0dXJuIHRoaXMub3JpZ2luYWxFdmVudFtlXSB9LCBzZXQ6IGZ1bmN0aW9uICh0KSB7IE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBlLCB7IGVudW1lcmFibGU6ICEwLCBjb25maWd1cmFibGU6ICEwLCB3cml0YWJsZTogITAsIHZhbHVlOiB0IH0pIH0gfSkgfSwgZml4OiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZVt3LmV4cGFuZG9dID8gZSA6IG5ldyB3LkV2ZW50KGUpIH0sIHNwZWNpYWw6IHsgbG9hZDogeyBub0J1YmJsZTogITAgfSwgZm9jdXM6IHsgdHJpZ2dlcjogZnVuY3Rpb24gKCkgeyBpZiAodGhpcyAhPT0ga2UoKSAmJiB0aGlzLmZvY3VzKSByZXR1cm4gdGhpcy5mb2N1cygpLCAhMSB9LCBkZWxlZ2F0ZVR5cGU6ICJmb2N1c2luIiB9LCBibHVyOiB7IHRyaWdnZXI6IGZ1bmN0aW9uICgpIHsgaWYgKHRoaXMgPT09IGtlKCkgJiYgdGhpcy5ibHVyKSByZXR1cm4gdGhpcy5ibHVyKCksICExIH0sIGRlbGVnYXRlVHlwZTogImZvY3Vzb3V0IiB9LCBjbGljazogeyB0cmlnZ2VyOiBmdW5jdGlvbiAoKSB7IGlmICgiY2hlY2tib3giID09PSB0aGlzLnR5cGUgJiYgdGhpcy5jbGljayAmJiBEKHRoaXMsICJpbnB1dCIpKSByZXR1cm4gdGhpcy5jbGljaygpLCAhMSB9LCBfZGVmYXVsdDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEQoZS50YXJnZXQsICJhIikgfSB9LCBiZWZvcmV1bmxvYWQ6IHsgcG9zdERpc3BhdGNoOiBmdW5jdGlvbiAoZSkgeyB2b2lkIDAgIT09IGUucmVzdWx0ICYmIGUub3JpZ2luYWxFdmVudCAmJiAoZS5vcmlnaW5hbEV2ZW50LnJldHVyblZhbHVlID0gZS5yZXN1bHQpIH0gfSB9IH0sIHcucmVtb3ZlRXZlbnQgPSBmdW5jdGlvbiAoZSwgdCwgbikgeyBlLnJlbW92ZUV2ZW50TGlzdGVuZXIgJiYgZS5yZW1vdmVFdmVudExpc3RlbmVyKHQsIG4pIH0sIHcuRXZlbnQgPSBmdW5jdGlvbiAoZSwgdCkgeyBpZiAoISh0aGlzIGluc3RhbmNlb2Ygdy5FdmVudCkpIHJldHVybiBuZXcgdy5FdmVudChlLCB0KTsgZSAmJiBlLnR5cGUgPyAodGhpcy5vcmlnaW5hbEV2ZW50ID0gZSwgdGhpcy50eXBlID0gZS50eXBlLCB0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IGUuZGVmYXVsdFByZXZlbnRlZCB8fCB2b2lkIDAgPT09IGUuZGVmYXVsdFByZXZlbnRlZCAmJiAhMSA9PT0gZS5yZXR1cm5WYWx1ZSA/IEVlIDogTmUsIHRoaXMudGFyZ2V0ID0gZS50YXJnZXQgJiYgMyA9PT0gZS50YXJnZXQubm9kZVR5cGUgPyBlLnRhcmdldC5wYXJlbnROb2RlIDogZS50YXJnZXQsIHRoaXMuY3VycmVudFRhcmdldCA9IGUuY3VycmVudFRhcmdldCwgdGhpcy5yZWxhdGVkVGFyZ2V0ID0gZS5yZWxhdGVkVGFyZ2V0KSA6IHRoaXMudHlwZSA9IGUsIHQgJiYgdy5leHRlbmQodGhpcywgdCksIHRoaXMudGltZVN0YW1wID0gZSAmJiBlLnRpbWVTdGFtcCB8fCBEYXRlLm5vdygpLCB0aGlzW3cuZXhwYW5kb10gPSAhMCB9LCB3LkV2ZW50LnByb3RvdHlwZSA9IHsgY29uc3RydWN0b3I6IHcuRXZlbnQsIGlzRGVmYXVsdFByZXZlbnRlZDogTmUsIGlzUHJvcGFnYXRpb25TdG9wcGVkOiBOZSwgaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQ6IE5lLCBpc1NpbXVsYXRlZDogITEsIHByZXZlbnREZWZhdWx0OiBmdW5jdGlvbiAoKSB7IHZhciBlID0gdGhpcy5vcmlnaW5hbEV2ZW50OyB0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IEVlLCBlICYmICF0aGlzLmlzU2ltdWxhdGVkICYmIGUucHJldmVudERlZmF1bHQoKSB9LCBzdG9wUHJvcGFnYXRpb246IGZ1bmN0aW9uICgpIHsgdmFyIGUgPSB0aGlzLm9yaWdpbmFsRXZlbnQ7IHRoaXMuaXNQcm9wYWdhdGlvblN0b3BwZWQgPSBFZSwgZSAmJiAhdGhpcy5pc1NpbXVsYXRlZCAmJiBlLnN0b3BQcm9wYWdhdGlvbigpIH0sIHN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbjogZnVuY3Rpb24gKCkgeyB2YXIgZSA9IHRoaXMub3JpZ2luYWxFdmVudDsgdGhpcy5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCA9IEVlLCBlICYmICF0aGlzLmlzU2ltdWxhdGVkICYmIGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCksIHRoaXMuc3RvcFByb3BhZ2F0aW9uKCkgfSB9LCB3LmVhY2goeyBhbHRLZXk6ICEwLCBidWJibGVzOiAhMCwgY2FuY2VsYWJsZTogITAsIGNoYW5nZWRUb3VjaGVzOiAhMCwgY3RybEtleTogITAsIGRldGFpbDogITAsIGV2ZW50UGhhc2U6ICEwLCBtZXRhS2V5OiAhMCwgcGFnZVg6ICEwLCBwYWdlWTogITAsIHNoaWZ0S2V5OiAhMCwgdmlldzogITAsICJjaGFyIjogITAsIGNoYXJDb2RlOiAhMCwga2V5OiAhMCwga2V5Q29kZTogITAsIGJ1dHRvbjogITAsIGJ1dHRvbnM6ICEwLCBjbGllbnRYOiAhMCwgY2xpZW50WTogITAsIG9mZnNldFg6ICEwLCBvZmZzZXRZOiAhMCwgcG9pbnRlcklkOiAhMCwgcG9pbnRlclR5cGU6ICEwLCBzY3JlZW5YOiAhMCwgc2NyZWVuWTogITAsIHRhcmdldFRvdWNoZXM6ICEwLCB0b0VsZW1lbnQ6ICEwLCB0b3VjaGVzOiAhMCwgd2hpY2g6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZS5idXR0b247IHJldHVybiBudWxsID09IGUud2hpY2ggJiYgd2UudGVzdChlLnR5cGUpID8gbnVsbCAhPSBlLmNoYXJDb2RlID8gZS5jaGFyQ29kZSA6IGUua2V5Q29kZSA6ICFlLndoaWNoICYmIHZvaWQgMCAhPT0gdCAmJiBDZS50ZXN0KGUudHlwZSkgPyAxICYgdCA/IDEgOiAyICYgdCA/IDMgOiA0ICYgdCA/IDIgOiAwIDogZS53aGljaCB9IH0sIHcuZXZlbnQuYWRkUHJvcCksIHcuZWFjaCh7IG1vdXNlZW50ZXI6ICJtb3VzZW92ZXIiLCBtb3VzZWxlYXZlOiAibW91c2VvdXQiLCBwb2ludGVyZW50ZXI6ICJwb2ludGVyb3ZlciIsIHBvaW50ZXJsZWF2ZTogInBvaW50ZXJvdXQiIH0sIGZ1bmN0aW9uIChlLCB0KSB7IHcuZXZlbnQuc3BlY2lhbFtlXSA9IHsgZGVsZWdhdGVUeXBlOiB0LCBiaW5kVHlwZTogdCwgaGFuZGxlOiBmdW5jdGlvbiAoZSkgeyB2YXIgbiwgciA9IHRoaXMsIGkgPSBlLnJlbGF0ZWRUYXJnZXQsIG8gPSBlLmhhbmRsZU9iajsgcmV0dXJuIGkgJiYgKGkgPT09IHIgfHwgdy5jb250YWlucyhyLCBpKSkgfHwgKGUudHlwZSA9IG8ub3JpZ1R5cGUsIG4gPSBvLmhhbmRsZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKSwgZS50eXBlID0gdCksIG4gfSB9IH0pLCB3LmZuLmV4dGVuZCh7IG9uOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyByZXR1cm4gQWUodGhpcywgZSwgdCwgbiwgcikgfSwgb25lOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyByZXR1cm4gQWUodGhpcywgZSwgdCwgbiwgciwgMSkgfSwgb2ZmOiBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciwgaTsgaWYgKGUgJiYgZS5wcmV2ZW50RGVmYXVsdCAmJiBlLmhhbmRsZU9iaikgcmV0dXJuIHIgPSBlLmhhbmRsZU9iaiwgdyhlLmRlbGVnYXRlVGFyZ2V0KS5vZmYoci5uYW1lc3BhY2UgPyByLm9yaWdUeXBlICsgIi4iICsgci5uYW1lc3BhY2UgOiByLm9yaWdUeXBlLCByLnNlbGVjdG9yLCByLmhhbmRsZXIpLCB0aGlzOyBpZiAoIm9iamVjdCIgPT0gdHlwZW9mIGUpIHsgZm9yIChpIGluIGUpIHRoaXMub2ZmKGksIHQsIGVbaV0pOyByZXR1cm4gdGhpcyB9IHJldHVybiAhMSAhPT0gdCAmJiAiZnVuY3Rpb24iICE9IHR5cGVvZiB0IHx8IChuID0gdCwgdCA9IHZvaWQgMCksICExID09PSBuICYmIChuID0gTmUpLCB0aGlzLmVhY2goZnVuY3Rpb24gKCkgeyB3LmV2ZW50LnJlbW92ZSh0aGlzLCBlLCBuLCB0KSB9KSB9IH0pOyB2YXIgRGUgPSAvPCg/IWFyZWF8YnJ8Y29sfGVtYmVkfGhyfGltZ3xpbnB1dHxsaW5rfG1ldGF8cGFyYW0pKChbYS16XVteXC9cMD5ceDIwXHRcclxuXGZdKilbXj5dKilcLz4vZ2ksIFNlID0gLzxzY3JpcHR8PHN0eWxlfDxsaW5rL2ksIExlID0gL2NoZWNrZWRccyooPzpbXj1dfD1ccyouY2hlY2tlZC4pL2ksIGplID0gL15ccyo8ISg/OlxbQ0RBVEFcW3wtLSl8KD86XF1cXXwtLSk+XHMqJC9nOyBmdW5jdGlvbiBxZShlLCB0KSB7IHJldHVybiBEKGUsICJ0YWJsZSIpICYmIEQoMTEgIT09IHQubm9kZVR5cGUgPyB0IDogdC5maXJzdENoaWxkLCAidHIiKSA/IHcoZSkuY2hpbGRyZW4oInRib2R5IilbMF0gfHwgZSA6IGUgfSBmdW5jdGlvbiBPZShlKSB7IHJldHVybiBlLnR5cGUgPSAobnVsbCAhPT0gZS5nZXRBdHRyaWJ1dGUoInR5cGUiKSkgKyAiLyIgKyBlLnR5cGUsIGUgfSBmdW5jdGlvbiBQZShlKSB7IHJldHVybiAidHJ1ZS8iID09PSAoZS50eXBlIHx8ICIiKS5zbGljZSgwLCA1KSA/IGUudHlwZSA9IGUudHlwZS5zbGljZSg1KSA6IGUucmVtb3ZlQXR0cmlidXRlKCJ0eXBlIiksIGUgfSBmdW5jdGlvbiBIZShlLCB0KSB7IHZhciBuLCByLCBpLCBvLCBhLCB1LCBzLCBsOyBpZiAoMSA9PT0gdC5ub2RlVHlwZSkgeyBpZiAoSy5oYXNEYXRhKGUpICYmIChvID0gSy5hY2Nlc3MoZSksIGEgPSBLLnNldCh0LCBvKSwgbCA9IG8uZXZlbnRzKSkgeyBkZWxldGUgYS5oYW5kbGUsIGEuZXZlbnRzID0ge307IGZvciAoaSBpbiBsKSBmb3IgKG4gPSAwLCByID0gbFtpXS5sZW5ndGg7IG4gPCByOyBuKyspdy5ldmVudC5hZGQodCwgaSwgbFtpXVtuXSkgfSBKLmhhc0RhdGEoZSkgJiYgKHUgPSBKLmFjY2VzcyhlKSwgcyA9IHcuZXh0ZW5kKHt9LCB1KSwgSi5zZXQodCwgcykpIH0gfSBmdW5jdGlvbiBJZShlLCB0KSB7IHZhciBuID0gdC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpOyAiaW5wdXQiID09PSBuICYmIGRlLnRlc3QoZS50eXBlKSA/IHQuY2hlY2tlZCA9IGUuY2hlY2tlZCA6ICJpbnB1dCIgIT09IG4gJiYgInRleHRhcmVhIiAhPT0gbiB8fCAodC5kZWZhdWx0VmFsdWUgPSBlLmRlZmF1bHRWYWx1ZSkgfSBmdW5jdGlvbiBSZShlLCB0LCBuLCByKSB7IHQgPSBhLmFwcGx5KFtdLCB0KTsgdmFyIGksIG8sIHUsIHMsIGwsIGMsIGYgPSAwLCBkID0gZS5sZW5ndGgsIHAgPSBkIC0gMSwgdiA9IHRbMF0sIHkgPSBnKHYpOyBpZiAoeSB8fCBkID4gMSAmJiAic3RyaW5nIiA9PSB0eXBlb2YgdiAmJiAhaC5jaGVja0Nsb25lICYmIExlLnRlc3QodikpIHJldHVybiBlLmVhY2goZnVuY3Rpb24gKGkpIHsgdmFyIG8gPSBlLmVxKGkpOyB5ICYmICh0WzBdID0gdi5jYWxsKHRoaXMsIGksIG8uaHRtbCgpKSksIFJlKG8sIHQsIG4sIHIpIH0pOyBpZiAoZCAmJiAoaSA9IGJlKHQsIGVbMF0ub3duZXJEb2N1bWVudCwgITEsIGUsIHIpLCBvID0gaS5maXJzdENoaWxkLCAxID09PSBpLmNoaWxkTm9kZXMubGVuZ3RoICYmIChpID0gbyksIG8gfHwgcikpIHsgZm9yIChzID0gKHUgPSB3Lm1hcCh2ZShpLCAic2NyaXB0IiksIE9lKSkubGVuZ3RoOyBmIDwgZDsgZisrKWwgPSBpLCBmICE9PSBwICYmIChsID0gdy5jbG9uZShsLCAhMCwgITApLCBzICYmIHcubWVyZ2UodSwgdmUobCwgInNjcmlwdCIpKSksIG4uY2FsbChlW2ZdLCBsLCBmKTsgaWYgKHMpIGZvciAoYyA9IHVbdS5sZW5ndGggLSAxXS5vd25lckRvY3VtZW50LCB3Lm1hcCh1LCBQZSksIGYgPSAwOyBmIDwgczsgZisrKWwgPSB1W2ZdLCBoZS50ZXN0KGwudHlwZSB8fCAiIikgJiYgIUsuYWNjZXNzKGwsICJnbG9iYWxFdmFsIikgJiYgdy5jb250YWlucyhjLCBsKSAmJiAobC5zcmMgJiYgIm1vZHVsZSIgIT09IChsLnR5cGUgfHwgIiIpLnRvTG93ZXJDYXNlKCkgPyB3Ll9ldmFsVXJsICYmIHcuX2V2YWxVcmwobC5zcmMpIDogbShsLnRleHRDb250ZW50LnJlcGxhY2UoamUsICIiKSwgYywgbCkpIH0gcmV0dXJuIGUgfSBmdW5jdGlvbiBCZShlLCB0LCBuKSB7IGZvciAodmFyIHIsIGkgPSB0ID8gdy5maWx0ZXIodCwgZSkgOiBlLCBvID0gMDsgbnVsbCAhPSAociA9IGlbb10pOyBvKyspbiB8fCAxICE9PSByLm5vZGVUeXBlIHx8IHcuY2xlYW5EYXRhKHZlKHIpKSwgci5wYXJlbnROb2RlICYmIChuICYmIHcuY29udGFpbnMoci5vd25lckRvY3VtZW50LCByKSAmJiB5ZSh2ZShyLCAic2NyaXB0IikpLCByLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQocikpOyByZXR1cm4gZSB9IHcuZXh0ZW5kKHsgaHRtbFByZWZpbHRlcjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUucmVwbGFjZShEZSwgIjwkMT48LyQyPiIpIH0sIGNsb25lOiBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciwgaSwgbywgYSwgdSA9IGUuY2xvbmVOb2RlKCEwKSwgcyA9IHcuY29udGFpbnMoZS5vd25lckRvY3VtZW50LCBlKTsgaWYgKCEoaC5ub0Nsb25lQ2hlY2tlZCB8fCAxICE9PSBlLm5vZGVUeXBlICYmIDExICE9PSBlLm5vZGVUeXBlIHx8IHcuaXNYTUxEb2MoZSkpKSBmb3IgKGEgPSB2ZSh1KSwgciA9IDAsIGkgPSAobyA9IHZlKGUpKS5sZW5ndGg7IHIgPCBpOyByKyspSWUob1tyXSwgYVtyXSk7IGlmICh0KSBpZiAobikgZm9yIChvID0gbyB8fCB2ZShlKSwgYSA9IGEgfHwgdmUodSksIHIgPSAwLCBpID0gby5sZW5ndGg7IHIgPCBpOyByKyspSGUob1tyXSwgYVtyXSk7IGVsc2UgSGUoZSwgdSk7IHJldHVybiAoYSA9IHZlKHUsICJzY3JpcHQiKSkubGVuZ3RoID4gMCAmJiB5ZShhLCAhcyAmJiB2ZShlLCAic2NyaXB0IikpLCB1IH0sIGNsZWFuRGF0YTogZnVuY3Rpb24gKGUpIHsgZm9yICh2YXIgdCwgbiwgciwgaSA9IHcuZXZlbnQuc3BlY2lhbCwgbyA9IDA7IHZvaWQgMCAhPT0gKG4gPSBlW29dKTsgbysrKWlmIChZKG4pKSB7IGlmICh0ID0gbltLLmV4cGFuZG9dKSB7IGlmICh0LmV2ZW50cykgZm9yIChyIGluIHQuZXZlbnRzKSBpW3JdID8gdy5ldmVudC5yZW1vdmUobiwgcikgOiB3LnJlbW92ZUV2ZW50KG4sIHIsIHQuaGFuZGxlKTsgbltLLmV4cGFuZG9dID0gdm9pZCAwIH0gbltKLmV4cGFuZG9dICYmIChuW0ouZXhwYW5kb10gPSB2b2lkIDApIH0gfSB9KSwgdy5mbi5leHRlbmQoeyBkZXRhY2g6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBCZSh0aGlzLCBlLCAhMCkgfSwgcmVtb3ZlOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gQmUodGhpcywgZSkgfSwgdGV4dDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIF8odGhpcywgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHZvaWQgMCA9PT0gZSA/IHcudGV4dCh0aGlzKSA6IHRoaXMuZW1wdHkoKS5lYWNoKGZ1bmN0aW9uICgpIHsgMSAhPT0gdGhpcy5ub2RlVHlwZSAmJiAxMSAhPT0gdGhpcy5ub2RlVHlwZSAmJiA5ICE9PSB0aGlzLm5vZGVUeXBlIHx8ICh0aGlzLnRleHRDb250ZW50ID0gZSkgfSkgfSwgbnVsbCwgZSwgYXJndW1lbnRzLmxlbmd0aCkgfSwgYXBwZW5kOiBmdW5jdGlvbiAoKSB7IHJldHVybiBSZSh0aGlzLCBhcmd1bWVudHMsIGZ1bmN0aW9uIChlKSB7IDEgIT09IHRoaXMubm9kZVR5cGUgJiYgMTEgIT09IHRoaXMubm9kZVR5cGUgJiYgOSAhPT0gdGhpcy5ub2RlVHlwZSB8fCBxZSh0aGlzLCBlKS5hcHBlbmRDaGlsZChlKSB9KSB9LCBwcmVwZW5kOiBmdW5jdGlvbiAoKSB7IHJldHVybiBSZSh0aGlzLCBhcmd1bWVudHMsIGZ1bmN0aW9uIChlKSB7IGlmICgxID09PSB0aGlzLm5vZGVUeXBlIHx8IDExID09PSB0aGlzLm5vZGVUeXBlIHx8IDkgPT09IHRoaXMubm9kZVR5cGUpIHsgdmFyIHQgPSBxZSh0aGlzLCBlKTsgdC5pbnNlcnRCZWZvcmUoZSwgdC5maXJzdENoaWxkKSB9IH0pIH0sIGJlZm9yZTogZnVuY3Rpb24gKCkgeyByZXR1cm4gUmUodGhpcywgYXJndW1lbnRzLCBmdW5jdGlvbiAoZSkgeyB0aGlzLnBhcmVudE5vZGUgJiYgdGhpcy5wYXJlbnROb2RlLmluc2VydEJlZm9yZShlLCB0aGlzKSB9KSB9LCBhZnRlcjogZnVuY3Rpb24gKCkgeyByZXR1cm4gUmUodGhpcywgYXJndW1lbnRzLCBmdW5jdGlvbiAoZSkgeyB0aGlzLnBhcmVudE5vZGUgJiYgdGhpcy5wYXJlbnROb2RlLmluc2VydEJlZm9yZShlLCB0aGlzLm5leHRTaWJsaW5nKSB9KSB9LCBlbXB0eTogZnVuY3Rpb24gKCkgeyBmb3IgKHZhciBlLCB0ID0gMDsgbnVsbCAhPSAoZSA9IHRoaXNbdF0pOyB0KyspMSA9PT0gZS5ub2RlVHlwZSAmJiAody5jbGVhbkRhdGEodmUoZSwgITEpKSwgZS50ZXh0Q29udGVudCA9ICIiKTsgcmV0dXJuIHRoaXMgfSwgY2xvbmU6IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiBlID0gbnVsbCAhPSBlICYmIGUsIHQgPSBudWxsID09IHQgPyBlIDogdCwgdGhpcy5tYXAoZnVuY3Rpb24gKCkgeyByZXR1cm4gdy5jbG9uZSh0aGlzLCBlLCB0KSB9KSB9LCBodG1sOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gXyh0aGlzLCBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IHRoaXNbMF0gfHwge30sIG4gPSAwLCByID0gdGhpcy5sZW5ndGg7IGlmICh2b2lkIDAgPT09IGUgJiYgMSA9PT0gdC5ub2RlVHlwZSkgcmV0dXJuIHQuaW5uZXJIVE1MOyBpZiAoInN0cmluZyIgPT0gdHlwZW9mIGUgJiYgIVNlLnRlc3QoZSkgJiYgIWdlWyhwZS5leGVjKGUpIHx8IFsiIiwgIiJdKVsxXS50b0xvd2VyQ2FzZSgpXSkgeyBlID0gdy5odG1sUHJlZmlsdGVyKGUpOyB0cnkgeyBmb3IgKDsgbiA8IHI7IG4rKykxID09PSAodCA9IHRoaXNbbl0gfHwge30pLm5vZGVUeXBlICYmICh3LmNsZWFuRGF0YSh2ZSh0LCAhMSkpLCB0LmlubmVySFRNTCA9IGUpOyB0ID0gMCB9IGNhdGNoIChlKSB7IH0gfSB0ICYmIHRoaXMuZW1wdHkoKS5hcHBlbmQoZSkgfSwgbnVsbCwgZSwgYXJndW1lbnRzLmxlbmd0aCkgfSwgcmVwbGFjZVdpdGg6IGZ1bmN0aW9uICgpIHsgdmFyIGUgPSBbXTsgcmV0dXJuIFJlKHRoaXMsIGFyZ3VtZW50cywgZnVuY3Rpb24gKHQpIHsgdmFyIG4gPSB0aGlzLnBhcmVudE5vZGU7IHcuaW5BcnJheSh0aGlzLCBlKSA8IDAgJiYgKHcuY2xlYW5EYXRhKHZlKHRoaXMpKSwgbiAmJiBuLnJlcGxhY2VDaGlsZCh0LCB0aGlzKSkgfSwgZSkgfSB9KSwgdy5lYWNoKHsgYXBwZW5kVG86ICJhcHBlbmQiLCBwcmVwZW5kVG86ICJwcmVwZW5kIiwgaW5zZXJ0QmVmb3JlOiAiYmVmb3JlIiwgaW5zZXJ0QWZ0ZXI6ICJhZnRlciIsIHJlcGxhY2VBbGw6ICJyZXBsYWNlV2l0aCIgfSwgZnVuY3Rpb24gKGUsIHQpIHsgdy5mbltlXSA9IGZ1bmN0aW9uIChlKSB7IGZvciAodmFyIG4sIHIgPSBbXSwgaSA9IHcoZSksIG8gPSBpLmxlbmd0aCAtIDEsIGEgPSAwOyBhIDw9IG87IGErKyluID0gYSA9PT0gbyA/IHRoaXMgOiB0aGlzLmNsb25lKCEwKSwgdyhpW2FdKVt0XShuKSwgdS5hcHBseShyLCBuLmdldCgpKTsgcmV0dXJuIHRoaXMucHVzaFN0YWNrKHIpIH0gfSk7IHZhciBNZSA9IG5ldyBSZWdFeHAoIl4oIiArIHJlICsgIikoPyFweClbYS16JV0rJCIsICJpIiksIFdlID0gZnVuY3Rpb24gKHQpIHsgdmFyIG4gPSB0Lm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXc7IHJldHVybiBuICYmIG4ub3BlbmVyIHx8IChuID0gZSksIG4uZ2V0Q29tcHV0ZWRTdHlsZSh0KSB9LCAkZSA9IG5ldyBSZWdFeHAob2Uuam9pbigifCIpLCAiaSIpOyAhZnVuY3Rpb24gKCkgeyBmdW5jdGlvbiB0KCkgeyBpZiAoYykgeyBsLnN0eWxlLmNzc1RleHQgPSAicG9zaXRpb246YWJzb2x1dGU7bGVmdDotMTExMTFweDt3aWR0aDo2MHB4O21hcmdpbi10b3A6MXB4O3BhZGRpbmc6MDtib3JkZXI6MCIsIGMuc3R5bGUuY3NzVGV4dCA9ICJwb3NpdGlvbjpyZWxhdGl2ZTtkaXNwbGF5OmJsb2NrO2JveC1zaXppbmc6Ym9yZGVyLWJveDtvdmVyZmxvdzpzY3JvbGw7bWFyZ2luOmF1dG87Ym9yZGVyOjFweDtwYWRkaW5nOjFweDt3aWR0aDo2MCU7dG9wOjElIiwgeGUuYXBwZW5kQ2hpbGQobCkuYXBwZW5kQ2hpbGQoYyk7IHZhciB0ID0gZS5nZXRDb21wdXRlZFN0eWxlKGMpOyBpID0gIjElIiAhPT0gdC50b3AsIHMgPSAxMiA9PT0gbih0Lm1hcmdpbkxlZnQpLCBjLnN0eWxlLnJpZ2h0ID0gIjYwJSIsIHUgPSAzNiA9PT0gbih0LnJpZ2h0KSwgbyA9IDM2ID09PSBuKHQud2lkdGgpLCBjLnN0eWxlLnBvc2l0aW9uID0gImFic29sdXRlIiwgYSA9IDM2ID09PSBjLm9mZnNldFdpZHRoIHx8ICJhYnNvbHV0ZSIsIHhlLnJlbW92ZUNoaWxkKGwpLCBjID0gbnVsbCB9IH0gZnVuY3Rpb24gbihlKSB7IHJldHVybiBNYXRoLnJvdW5kKHBhcnNlRmxvYXQoZSkpIH0gdmFyIGksIG8sIGEsIHUsIHMsIGwgPSByLmNyZWF0ZUVsZW1lbnQoImRpdiIpLCBjID0gci5jcmVhdGVFbGVtZW50KCJkaXYiKTsgYy5zdHlsZSAmJiAoYy5zdHlsZS5iYWNrZ3JvdW5kQ2xpcCA9ICJjb250ZW50LWJveCIsIGMuY2xvbmVOb2RlKCEwKS5zdHlsZS5iYWNrZ3JvdW5kQ2xpcCA9ICIiLCBoLmNsZWFyQ2xvbmVTdHlsZSA9ICJjb250ZW50LWJveCIgPT09IGMuc3R5bGUuYmFja2dyb3VuZENsaXAsIHcuZXh0ZW5kKGgsIHsgYm94U2l6aW5nUmVsaWFibGU6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHQoKSwgbyB9LCBwaXhlbEJveFN0eWxlczogZnVuY3Rpb24gKCkgeyByZXR1cm4gdCgpLCB1IH0sIHBpeGVsUG9zaXRpb246IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHQoKSwgaSB9LCByZWxpYWJsZU1hcmdpbkxlZnQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHQoKSwgcyB9LCBzY3JvbGxib3hTaXplOiBmdW5jdGlvbiAoKSB7IHJldHVybiB0KCksIGEgfSB9KSkgfSgpOyBmdW5jdGlvbiBGZShlLCB0LCBuKSB7IHZhciByLCBpLCBvLCBhLCB1ID0gZS5zdHlsZTsgcmV0dXJuIChuID0gbiB8fCBXZShlKSkgJiYgKCIiICE9PSAoYSA9IG4uZ2V0UHJvcGVydHlWYWx1ZSh0KSB8fCBuW3RdKSB8fCB3LmNvbnRhaW5zKGUub3duZXJEb2N1bWVudCwgZSkgfHwgKGEgPSB3LnN0eWxlKGUsIHQpKSwgIWgucGl4ZWxCb3hTdHlsZXMoKSAmJiBNZS50ZXN0KGEpICYmICRlLnRlc3QodCkgJiYgKHIgPSB1LndpZHRoLCBpID0gdS5taW5XaWR0aCwgbyA9IHUubWF4V2lkdGgsIHUubWluV2lkdGggPSB1Lm1heFdpZHRoID0gdS53aWR0aCA9IGEsIGEgPSBuLndpZHRoLCB1LndpZHRoID0gciwgdS5taW5XaWR0aCA9IGksIHUubWF4V2lkdGggPSBvKSksIHZvaWQgMCAhPT0gYSA/IGEgKyAiIiA6IGEgfSBmdW5jdGlvbiB6ZShlLCB0KSB7IHJldHVybiB7IGdldDogZnVuY3Rpb24gKCkgeyBpZiAoIWUoKSkgcmV0dXJuICh0aGlzLmdldCA9IHQpLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IGRlbGV0ZSB0aGlzLmdldCB9IH0gfSB2YXIgX2UgPSAvXihub25lfHRhYmxlKD8hLWNbZWFdKS4rKS8sIFVlID0gL14tLS8sIFZlID0geyBwb3NpdGlvbjogImFic29sdXRlIiwgdmlzaWJpbGl0eTogImhpZGRlbiIsIGRpc3BsYXk6ICJibG9jayIgfSwgWGUgPSB7IGxldHRlclNwYWNpbmc6ICIwIiwgZm9udFdlaWdodDogIjQwMCIgfSwgUWUgPSBbIldlYmtpdCIsICJNb3oiLCAibXMiXSwgWWUgPSByLmNyZWF0ZUVsZW1lbnQoImRpdiIpLnN0eWxlOyBmdW5jdGlvbiBHZShlKSB7IGlmIChlIGluIFllKSByZXR1cm4gZTsgdmFyIHQgPSBlWzBdLnRvVXBwZXJDYXNlKCkgKyBlLnNsaWNlKDEpLCBuID0gUWUubGVuZ3RoOyB3aGlsZSAobi0tKSBpZiAoKGUgPSBRZVtuXSArIHQpIGluIFllKSByZXR1cm4gZSB9IGZ1bmN0aW9uIEtlKGUpIHsgdmFyIHQgPSB3LmNzc1Byb3BzW2VdOyByZXR1cm4gdCB8fCAodCA9IHcuY3NzUHJvcHNbZV0gPSBHZShlKSB8fCBlKSwgdCB9IGZ1bmN0aW9uIEplKGUsIHQsIG4pIHsgdmFyIHIgPSBpZS5leGVjKHQpOyByZXR1cm4gciA/IE1hdGgubWF4KDAsIHJbMl0gLSAobiB8fCAwKSkgKyAoclszXSB8fCAicHgiKSA6IHQgfSBmdW5jdGlvbiBaZShlLCB0LCBuLCByLCBpLCBvKSB7IHZhciBhID0gIndpZHRoIiA9PT0gdCA/IDEgOiAwLCB1ID0gMCwgcyA9IDA7IGlmIChuID09PSAociA/ICJib3JkZXIiIDogImNvbnRlbnQiKSkgcmV0dXJuIDA7IGZvciAoOyBhIDwgNDsgYSArPSAyKSJtYXJnaW4iID09PSBuICYmIChzICs9IHcuY3NzKGUsIG4gKyBvZVthXSwgITAsIGkpKSwgciA/ICgiY29udGVudCIgPT09IG4gJiYgKHMgLT0gdy5jc3MoZSwgInBhZGRpbmciICsgb2VbYV0sICEwLCBpKSksICJtYXJnaW4iICE9PSBuICYmIChzIC09IHcuY3NzKGUsICJib3JkZXIiICsgb2VbYV0gKyAiV2lkdGgiLCAhMCwgaSkpKSA6IChzICs9IHcuY3NzKGUsICJwYWRkaW5nIiArIG9lW2FdLCAhMCwgaSksICJwYWRkaW5nIiAhPT0gbiA/IHMgKz0gdy5jc3MoZSwgImJvcmRlciIgKyBvZVthXSArICJXaWR0aCIsICEwLCBpKSA6IHUgKz0gdy5jc3MoZSwgImJvcmRlciIgKyBvZVthXSArICJXaWR0aCIsICEwLCBpKSk7IHJldHVybiAhciAmJiBvID49IDAgJiYgKHMgKz0gTWF0aC5tYXgoMCwgTWF0aC5jZWlsKGVbIm9mZnNldCIgKyB0WzBdLnRvVXBwZXJDYXNlKCkgKyB0LnNsaWNlKDEpXSAtIG8gLSBzIC0gdSAtIC41KSkpLCBzIH0gZnVuY3Rpb24gZXQoZSwgdCwgbikgeyB2YXIgciA9IFdlKGUpLCBpID0gRmUoZSwgdCwgciksIG8gPSAiYm9yZGVyLWJveCIgPT09IHcuY3NzKGUsICJib3hTaXppbmciLCAhMSwgciksIGEgPSBvOyBpZiAoTWUudGVzdChpKSkgeyBpZiAoIW4pIHJldHVybiBpOyBpID0gImF1dG8iIH0gcmV0dXJuIGEgPSBhICYmIChoLmJveFNpemluZ1JlbGlhYmxlKCkgfHwgaSA9PT0gZS5zdHlsZVt0XSksICgiYXV0byIgPT09IGkgfHwgIXBhcnNlRmxvYXQoaSkgJiYgImlubGluZSIgPT09IHcuY3NzKGUsICJkaXNwbGF5IiwgITEsIHIpKSAmJiAoaSA9IGVbIm9mZnNldCIgKyB0WzBdLnRvVXBwZXJDYXNlKCkgKyB0LnNsaWNlKDEpXSwgYSA9ICEwKSwgKGkgPSBwYXJzZUZsb2F0KGkpIHx8IDApICsgWmUoZSwgdCwgbiB8fCAobyA/ICJib3JkZXIiIDogImNvbnRlbnQiKSwgYSwgciwgaSkgKyAicHgiIH0gdy5leHRlbmQoeyBjc3NIb29rczogeyBvcGFjaXR5OiB7IGdldDogZnVuY3Rpb24gKGUsIHQpIHsgaWYgKHQpIHsgdmFyIG4gPSBGZShlLCAib3BhY2l0eSIpOyByZXR1cm4gIiIgPT09IG4gPyAiMSIgOiBuIH0gfSB9IH0sIGNzc051bWJlcjogeyBhbmltYXRpb25JdGVyYXRpb25Db3VudDogITAsIGNvbHVtbkNvdW50OiAhMCwgZmlsbE9wYWNpdHk6ICEwLCBmbGV4R3JvdzogITAsIGZsZXhTaHJpbms6ICEwLCBmb250V2VpZ2h0OiAhMCwgbGluZUhlaWdodDogITAsIG9wYWNpdHk6ICEwLCBvcmRlcjogITAsIG9ycGhhbnM6ICEwLCB3aWRvd3M6ICEwLCB6SW5kZXg6ICEwLCB6b29tOiAhMCB9LCBjc3NQcm9wczoge30sIHN0eWxlOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyBpZiAoZSAmJiAzICE9PSBlLm5vZGVUeXBlICYmIDggIT09IGUubm9kZVR5cGUgJiYgZS5zdHlsZSkgeyB2YXIgaSwgbywgYSwgdSA9IFEodCksIHMgPSBVZS50ZXN0KHQpLCBsID0gZS5zdHlsZTsgaWYgKHMgfHwgKHQgPSBLZSh1KSksIGEgPSB3LmNzc0hvb2tzW3RdIHx8IHcuY3NzSG9va3NbdV0sIHZvaWQgMCA9PT0gbikgcmV0dXJuIGEgJiYgImdldCIgaW4gYSAmJiB2b2lkIDAgIT09IChpID0gYS5nZXQoZSwgITEsIHIpKSA/IGkgOiBsW3RdOyAic3RyaW5nIiA9PSAobyA9IHR5cGVvZiBuKSAmJiAoaSA9IGllLmV4ZWMobikpICYmIGlbMV0gJiYgKG4gPSBzZShlLCB0LCBpKSwgbyA9ICJudW1iZXIiKSwgbnVsbCAhPSBuICYmIG4gPT09IG4gJiYgKCJudW1iZXIiID09PSBvICYmIChuICs9IGkgJiYgaVszXSB8fCAody5jc3NOdW1iZXJbdV0gPyAiIiA6ICJweCIpKSwgaC5jbGVhckNsb25lU3R5bGUgfHwgIiIgIT09IG4gfHwgMCAhPT0gdC5pbmRleE9mKCJiYWNrZ3JvdW5kIikgfHwgKGxbdF0gPSAiaW5oZXJpdCIpLCBhICYmICJzZXQiIGluIGEgJiYgdm9pZCAwID09PSAobiA9IGEuc2V0KGUsIG4sIHIpKSB8fCAocyA/IGwuc2V0UHJvcGVydHkodCwgbikgOiBsW3RdID0gbikpIH0gfSwgY3NzOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyB2YXIgaSwgbywgYSwgdSA9IFEodCk7IHJldHVybiBVZS50ZXN0KHQpIHx8ICh0ID0gS2UodSkpLCAoYSA9IHcuY3NzSG9va3NbdF0gfHwgdy5jc3NIb29rc1t1XSkgJiYgImdldCIgaW4gYSAmJiAoaSA9IGEuZ2V0KGUsICEwLCBuKSksIHZvaWQgMCA9PT0gaSAmJiAoaSA9IEZlKGUsIHQsIHIpKSwgIm5vcm1hbCIgPT09IGkgJiYgdCBpbiBYZSAmJiAoaSA9IFhlW3RdKSwgIiIgPT09IG4gfHwgbiA/IChvID0gcGFyc2VGbG9hdChpKSwgITAgPT09IG4gfHwgaXNGaW5pdGUobykgPyBvIHx8IDAgOiBpKSA6IGkgfSB9KSwgdy5lYWNoKFsiaGVpZ2h0IiwgIndpZHRoIl0sIGZ1bmN0aW9uIChlLCB0KSB7IHcuY3NzSG9va3NbdF0gPSB7IGdldDogZnVuY3Rpb24gKGUsIG4sIHIpIHsgaWYgKG4pIHJldHVybiAhX2UudGVzdCh3LmNzcyhlLCAiZGlzcGxheSIpKSB8fCBlLmdldENsaWVudFJlY3RzKCkubGVuZ3RoICYmIGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGggPyBldChlLCB0LCByKSA6IHVlKGUsIFZlLCBmdW5jdGlvbiAoKSB7IHJldHVybiBldChlLCB0LCByKSB9KSB9LCBzZXQ6IGZ1bmN0aW9uIChlLCBuLCByKSB7IHZhciBpLCBvID0gV2UoZSksIGEgPSAiYm9yZGVyLWJveCIgPT09IHcuY3NzKGUsICJib3hTaXppbmciLCAhMSwgbyksIHUgPSByICYmIFplKGUsIHQsIHIsIGEsIG8pOyByZXR1cm4gYSAmJiBoLnNjcm9sbGJveFNpemUoKSA9PT0gby5wb3NpdGlvbiAmJiAodSAtPSBNYXRoLmNlaWwoZVsib2Zmc2V0IiArIHRbMF0udG9VcHBlckNhc2UoKSArIHQuc2xpY2UoMSldIC0gcGFyc2VGbG9hdChvW3RdKSAtIFplKGUsIHQsICJib3JkZXIiLCAhMSwgbykgLSAuNSkpLCB1ICYmIChpID0gaWUuZXhlYyhuKSkgJiYgInB4IiAhPT0gKGlbM10gfHwgInB4IikgJiYgKGUuc3R5bGVbdF0gPSBuLCBuID0gdy5jc3MoZSwgdCkpLCBKZShlLCBuLCB1KSB9IH0gfSksIHcuY3NzSG9va3MubWFyZ2luTGVmdCA9IHplKGgucmVsaWFibGVNYXJnaW5MZWZ0LCBmdW5jdGlvbiAoZSwgdCkgeyBpZiAodCkgcmV0dXJuIChwYXJzZUZsb2F0KEZlKGUsICJtYXJnaW5MZWZ0IikpIHx8IGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkubGVmdCAtIHVlKGUsIHsgbWFyZ2luTGVmdDogMCB9LCBmdW5jdGlvbiAoKSB7IHJldHVybiBlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQgfSkpICsgInB4IiB9KSwgdy5lYWNoKHsgbWFyZ2luOiAiIiwgcGFkZGluZzogIiIsIGJvcmRlcjogIldpZHRoIiB9LCBmdW5jdGlvbiAoZSwgdCkgeyB3LmNzc0hvb2tzW2UgKyB0XSA9IHsgZXhwYW5kOiBmdW5jdGlvbiAobikgeyBmb3IgKHZhciByID0gMCwgaSA9IHt9LCBvID0gInN0cmluZyIgPT0gdHlwZW9mIG4gPyBuLnNwbGl0KCIgIikgOiBbbl07IHIgPCA0OyByKyspaVtlICsgb2Vbcl0gKyB0XSA9IG9bcl0gfHwgb1tyIC0gMl0gfHwgb1swXTsgcmV0dXJuIGkgfSB9LCAibWFyZ2luIiAhPT0gZSAmJiAody5jc3NIb29rc1tlICsgdF0uc2V0ID0gSmUpIH0pLCB3LmZuLmV4dGVuZCh7IGNzczogZnVuY3Rpb24gKGUsIHQpIHsgcmV0dXJuIF8odGhpcywgZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIsIGksIG8gPSB7fSwgYSA9IDA7IGlmIChBcnJheS5pc0FycmF5KHQpKSB7IGZvciAociA9IFdlKGUpLCBpID0gdC5sZW5ndGg7IGEgPCBpOyBhKyspb1t0W2FdXSA9IHcuY3NzKGUsIHRbYV0sICExLCByKTsgcmV0dXJuIG8gfSByZXR1cm4gdm9pZCAwICE9PSBuID8gdy5zdHlsZShlLCB0LCBuKSA6IHcuY3NzKGUsIHQpIH0sIGUsIHQsIGFyZ3VtZW50cy5sZW5ndGggPiAxKSB9IH0pLCB3LmZuLmRlbGF5ID0gZnVuY3Rpb24gKHQsIG4pIHsgcmV0dXJuIHQgPSB3LmZ4ID8gdy5meC5zcGVlZHNbdF0gfHwgdCA6IHQsIG4gPSBuIHx8ICJmeCIsIHRoaXMucXVldWUobiwgZnVuY3Rpb24gKG4sIHIpIHsgdmFyIGkgPSBlLnNldFRpbWVvdXQobiwgdCk7IHIuc3RvcCA9IGZ1bmN0aW9uICgpIHsgZS5jbGVhclRpbWVvdXQoaSkgfSB9KSB9LCBmdW5jdGlvbiAoKSB7IHZhciBlID0gci5jcmVhdGVFbGVtZW50KCJpbnB1dCIpLCB0ID0gci5jcmVhdGVFbGVtZW50KCJzZWxlY3QiKS5hcHBlbmRDaGlsZChyLmNyZWF0ZUVsZW1lbnQoIm9wdGlvbiIpKTsgZS50eXBlID0gImNoZWNrYm94IiwgaC5jaGVja09uID0gIiIgIT09IGUudmFsdWUsIGgub3B0U2VsZWN0ZWQgPSB0LnNlbGVjdGVkLCAoZSA9IHIuY3JlYXRlRWxlbWVudCgiaW5wdXQiKSkudmFsdWUgPSAidCIsIGUudHlwZSA9ICJyYWRpbyIsIGgucmFkaW9WYWx1ZSA9ICJ0IiA9PT0gZS52YWx1ZSB9KCk7IHZhciB0dCwgbnQgPSB3LmV4cHIuYXR0ckhhbmRsZTsgdy5mbi5leHRlbmQoeyBhdHRyOiBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gXyh0aGlzLCB3LmF0dHIsIGUsIHQsIGFyZ3VtZW50cy5sZW5ndGggPiAxKSB9LCByZW1vdmVBdHRyOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgdy5yZW1vdmVBdHRyKHRoaXMsIGUpIH0pIH0gfSksIHcuZXh0ZW5kKHsgYXR0cjogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIsIGksIG8gPSBlLm5vZGVUeXBlOyBpZiAoMyAhPT0gbyAmJiA4ICE9PSBvICYmIDIgIT09IG8pIHJldHVybiAidW5kZWZpbmVkIiA9PSB0eXBlb2YgZS5nZXRBdHRyaWJ1dGUgPyB3LnByb3AoZSwgdCwgbikgOiAoMSA9PT0gbyAmJiB3LmlzWE1MRG9jKGUpIHx8IChpID0gdy5hdHRySG9va3NbdC50b0xvd2VyQ2FzZSgpXSB8fCAody5leHByLm1hdGNoLmJvb2wudGVzdCh0KSA/IHR0IDogdm9pZCAwKSksIHZvaWQgMCAhPT0gbiA/IG51bGwgPT09IG4gPyB2b2lkIHcucmVtb3ZlQXR0cihlLCB0KSA6IGkgJiYgInNldCIgaW4gaSAmJiB2b2lkIDAgIT09IChyID0gaS5zZXQoZSwgbiwgdCkpID8gciA6IChlLnNldEF0dHJpYnV0ZSh0LCBuICsgIiIpLCBuKSA6IGkgJiYgImdldCIgaW4gaSAmJiBudWxsICE9PSAociA9IGkuZ2V0KGUsIHQpKSA/IHIgOiBudWxsID09IChyID0gdy5maW5kLmF0dHIoZSwgdCkpID8gdm9pZCAwIDogcikgfSwgYXR0ckhvb2tzOiB7IHR5cGU6IHsgc2V0OiBmdW5jdGlvbiAoZSwgdCkgeyBpZiAoIWgucmFkaW9WYWx1ZSAmJiAicmFkaW8iID09PSB0ICYmIEQoZSwgImlucHV0IikpIHsgdmFyIG4gPSBlLnZhbHVlOyByZXR1cm4gZS5zZXRBdHRyaWJ1dGUoInR5cGUiLCB0KSwgbiAmJiAoZS52YWx1ZSA9IG4pLCB0IH0gfSB9IH0sIHJlbW92ZUF0dHI6IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCByID0gMCwgaSA9IHQgJiYgdC5tYXRjaChJKTsgaWYgKGkgJiYgMSA9PT0gZS5ub2RlVHlwZSkgd2hpbGUgKG4gPSBpW3IrK10pIGUucmVtb3ZlQXR0cmlidXRlKG4pIH0gfSksIHR0ID0geyBzZXQ6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiAhMSA9PT0gdCA/IHcucmVtb3ZlQXR0cihlLCBuKSA6IGUuc2V0QXR0cmlidXRlKG4sIG4pLCBuIH0gfSwgdy5lYWNoKHcuZXhwci5tYXRjaC5ib29sLnNvdXJjZS5tYXRjaCgvXHcrL2cpLCBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IG50W3RdIHx8IHcuZmluZC5hdHRyOyBudFt0XSA9IGZ1bmN0aW9uIChlLCB0LCByKSB7IHZhciBpLCBvLCBhID0gdC50b0xvd2VyQ2FzZSgpOyByZXR1cm4gciB8fCAobyA9IG50W2FdLCBudFthXSA9IGksIGkgPSBudWxsICE9IG4oZSwgdCwgcikgPyBhIDogbnVsbCwgbnRbYV0gPSBvKSwgaSB9IH0pOyB2YXIgcnQgPSAvXig/OmlucHV0fHNlbGVjdHx0ZXh0YXJlYXxidXR0b24pJC9pLCBpdCA9IC9eKD86YXxhcmVhKSQvaTsgdy5mbi5leHRlbmQoeyBwcm9wOiBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gXyh0aGlzLCB3LnByb3AsIGUsIHQsIGFyZ3VtZW50cy5sZW5ndGggPiAxKSB9LCByZW1vdmVQcm9wOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgZGVsZXRlIHRoaXNbdy5wcm9wRml4W2VdIHx8IGVdIH0pIH0gfSksIHcuZXh0ZW5kKHsgcHJvcDogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIsIGksIG8gPSBlLm5vZGVUeXBlOyBpZiAoMyAhPT0gbyAmJiA4ICE9PSBvICYmIDIgIT09IG8pIHJldHVybiAxID09PSBvICYmIHcuaXNYTUxEb2MoZSkgfHwgKHQgPSB3LnByb3BGaXhbdF0gfHwgdCwgaSA9IHcucHJvcEhvb2tzW3RdKSwgdm9pZCAwICE9PSBuID8gaSAmJiAic2V0IiBpbiBpICYmIHZvaWQgMCAhPT0gKHIgPSBpLnNldChlLCBuLCB0KSkgPyByIDogZVt0XSA9IG4gOiBpICYmICJnZXQiIGluIGkgJiYgbnVsbCAhPT0gKHIgPSBpLmdldChlLCB0KSkgPyByIDogZVt0XSB9LCBwcm9wSG9va3M6IHsgdGFiSW5kZXg6IHsgZ2V0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IHcuZmluZC5hdHRyKGUsICJ0YWJpbmRleCIpOyByZXR1cm4gdCA/IHBhcnNlSW50KHQsIDEwKSA6IHJ0LnRlc3QoZS5ub2RlTmFtZSkgfHwgaXQudGVzdChlLm5vZGVOYW1lKSAmJiBlLmhyZWYgPyAwIDogLTEgfSB9IH0sIHByb3BGaXg6IHsgImZvciI6ICJodG1sRm9yIiwgImNsYXNzIjogImNsYXNzTmFtZSIgfSB9KSwgaC5vcHRTZWxlY3RlZCB8fCAody5wcm9wSG9va3Muc2VsZWN0ZWQgPSB7IGdldDogZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSBlLnBhcmVudE5vZGU7IHJldHVybiB0ICYmIHQucGFyZW50Tm9kZSAmJiB0LnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleCwgbnVsbCB9LCBzZXQ6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZS5wYXJlbnROb2RlOyB0ICYmICh0LnNlbGVjdGVkSW5kZXgsIHQucGFyZW50Tm9kZSAmJiB0LnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleCkgfSB9KSwgdy5lYWNoKFsidGFiSW5kZXgiLCAicmVhZE9ubHkiLCAibWF4TGVuZ3RoIiwgImNlbGxTcGFjaW5nIiwgImNlbGxQYWRkaW5nIiwgInJvd1NwYW4iLCAiY29sU3BhbiIsICJ1c2VNYXAiLCAiZnJhbWVCb3JkZXIiLCAiY29udGVudEVkaXRhYmxlIl0sIGZ1bmN0aW9uICgpIHsgdy5wcm9wRml4W3RoaXMudG9Mb3dlckNhc2UoKV0gPSB0aGlzIH0pOyBmdW5jdGlvbiBvdChlKSB7IHJldHVybiAoZS5tYXRjaChJKSB8fCBbXSkuam9pbigiICIpIH0gZnVuY3Rpb24gYXQoZSkgeyByZXR1cm4gZS5nZXRBdHRyaWJ1dGUgJiYgZS5nZXRBdHRyaWJ1dGUoImNsYXNzIikgfHwgIiIgfSBmdW5jdGlvbiB1dChlKSB7IHJldHVybiBBcnJheS5pc0FycmF5KGUpID8gZSA6ICJzdHJpbmciID09IHR5cGVvZiBlID8gZS5tYXRjaChJKSB8fCBbXSA6IFtdIH0gdy5mbi5leHRlbmQoeyBhZGRDbGFzczogZnVuY3Rpb24gKGUpIHsgdmFyIHQsIG4sIHIsIGksIG8sIGEsIHUsIHMgPSAwOyBpZiAoZyhlKSkgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAodCkgeyB3KHRoaXMpLmFkZENsYXNzKGUuY2FsbCh0aGlzLCB0LCBhdCh0aGlzKSkpIH0pOyBpZiAoKHQgPSB1dChlKSkubGVuZ3RoKSB3aGlsZSAobiA9IHRoaXNbcysrXSkgaWYgKGkgPSBhdChuKSwgciA9IDEgPT09IG4ubm9kZVR5cGUgJiYgIiAiICsgb3QoaSkgKyAiICIpIHsgYSA9IDA7IHdoaWxlIChvID0gdFthKytdKSByLmluZGV4T2YoIiAiICsgbyArICIgIikgPCAwICYmIChyICs9IG8gKyAiICIpOyBpICE9PSAodSA9IG90KHIpKSAmJiBuLnNldEF0dHJpYnV0ZSgiY2xhc3MiLCB1KSB9IHJldHVybiB0aGlzIH0sIHJlbW92ZUNsYXNzOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgbiwgciwgaSwgbywgYSwgdSwgcyA9IDA7IGlmIChnKGUpKSByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICh0KSB7IHcodGhpcykucmVtb3ZlQ2xhc3MoZS5jYWxsKHRoaXMsIHQsIGF0KHRoaXMpKSkgfSk7IGlmICghYXJndW1lbnRzLmxlbmd0aCkgcmV0dXJuIHRoaXMuYXR0cigiY2xhc3MiLCAiIik7IGlmICgodCA9IHV0KGUpKS5sZW5ndGgpIHdoaWxlIChuID0gdGhpc1tzKytdKSBpZiAoaSA9IGF0KG4pLCByID0gMSA9PT0gbi5ub2RlVHlwZSAmJiAiICIgKyBvdChpKSArICIgIikgeyBhID0gMDsgd2hpbGUgKG8gPSB0W2ErK10pIHdoaWxlIChyLmluZGV4T2YoIiAiICsgbyArICIgIikgPiAtMSkgciA9IHIucmVwbGFjZSgiICIgKyBvICsgIiAiLCAiICIpOyBpICE9PSAodSA9IG90KHIpKSAmJiBuLnNldEF0dHJpYnV0ZSgiY2xhc3MiLCB1KSB9IHJldHVybiB0aGlzIH0sIHRvZ2dsZUNsYXNzOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IHR5cGVvZiBlLCByID0gInN0cmluZyIgPT09IG4gfHwgQXJyYXkuaXNBcnJheShlKTsgcmV0dXJuICJib29sZWFuIiA9PSB0eXBlb2YgdCAmJiByID8gdCA/IHRoaXMuYWRkQ2xhc3MoZSkgOiB0aGlzLnJlbW92ZUNsYXNzKGUpIDogZyhlKSA/IHRoaXMuZWFjaChmdW5jdGlvbiAobikgeyB3KHRoaXMpLnRvZ2dsZUNsYXNzKGUuY2FsbCh0aGlzLCBuLCBhdCh0aGlzKSwgdCksIHQpIH0pIDogdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgdmFyIHQsIGksIG8sIGE7IGlmIChyKSB7IGkgPSAwLCBvID0gdyh0aGlzKSwgYSA9IHV0KGUpOyB3aGlsZSAodCA9IGFbaSsrXSkgby5oYXNDbGFzcyh0KSA/IG8ucmVtb3ZlQ2xhc3ModCkgOiBvLmFkZENsYXNzKHQpIH0gZWxzZSB2b2lkIDAgIT09IGUgJiYgImJvb2xlYW4iICE9PSBuIHx8ICgodCA9IGF0KHRoaXMpKSAmJiBLLnNldCh0aGlzLCAiX19jbGFzc05hbWVfXyIsIHQpLCB0aGlzLnNldEF0dHJpYnV0ZSAmJiB0aGlzLnNldEF0dHJpYnV0ZSgiY2xhc3MiLCB0IHx8ICExID09PSBlID8gIiIgOiBLLmdldCh0aGlzLCAiX19jbGFzc05hbWVfXyIpIHx8ICIiKSkgfSkgfSwgaGFzQ2xhc3M6IGZ1bmN0aW9uIChlKSB7IHZhciB0LCBuLCByID0gMDsgdCA9ICIgIiArIGUgKyAiICI7IHdoaWxlIChuID0gdGhpc1tyKytdKSBpZiAoMSA9PT0gbi5ub2RlVHlwZSAmJiAoIiAiICsgb3QoYXQobikpICsgIiAiKS5pbmRleE9mKHQpID4gLTEpIHJldHVybiAhMDsgcmV0dXJuICExIH0gfSk7IHZhciBzdCA9IC9cci9nOyB3LmZuLmV4dGVuZCh7IHZhbDogZnVuY3Rpb24gKGUpIHsgdmFyIHQsIG4sIHIsIGkgPSB0aGlzWzBdOyB7IGlmIChhcmd1bWVudHMubGVuZ3RoKSByZXR1cm4gciA9IGcoZSksIHRoaXMuZWFjaChmdW5jdGlvbiAobikgeyB2YXIgaTsgMSA9PT0gdGhpcy5ub2RlVHlwZSAmJiAobnVsbCA9PSAoaSA9IHIgPyBlLmNhbGwodGhpcywgbiwgdyh0aGlzKS52YWwoKSkgOiBlKSA/IGkgPSAiIiA6ICJudW1iZXIiID09IHR5cGVvZiBpID8gaSArPSAiIiA6IEFycmF5LmlzQXJyYXkoaSkgJiYgKGkgPSB3Lm1hcChpLCBmdW5jdGlvbiAoZSkgeyByZXR1cm4gbnVsbCA9PSBlID8gIiIgOiBlICsgIiIgfSkpLCAodCA9IHcudmFsSG9va3NbdGhpcy50eXBlXSB8fCB3LnZhbEhvb2tzW3RoaXMubm9kZU5hbWUudG9Mb3dlckNhc2UoKV0pICYmICJzZXQiIGluIHQgJiYgdm9pZCAwICE9PSB0LnNldCh0aGlzLCBpLCAidmFsdWUiKSB8fCAodGhpcy52YWx1ZSA9IGkpKSB9KTsgaWYgKGkpIHJldHVybiAodCA9IHcudmFsSG9va3NbaS50eXBlXSB8fCB3LnZhbEhvb2tzW2kubm9kZU5hbWUudG9Mb3dlckNhc2UoKV0pICYmICJnZXQiIGluIHQgJiYgdm9pZCAwICE9PSAobiA9IHQuZ2V0KGksICJ2YWx1ZSIpKSA/IG4gOiAic3RyaW5nIiA9PSB0eXBlb2YgKG4gPSBpLnZhbHVlKSA/IG4ucmVwbGFjZShzdCwgIiIpIDogbnVsbCA9PSBuID8gIiIgOiBuIH0gfSB9KSwgdy5leHRlbmQoeyB2YWxIb29rczogeyBvcHRpb246IHsgZ2V0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IHcuZmluZC5hdHRyKGUsICJ2YWx1ZSIpOyByZXR1cm4gbnVsbCAhPSB0ID8gdCA6IG90KHcudGV4dChlKSkgfSB9LCBzZWxlY3Q6IHsgZ2V0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgbiwgciwgaSA9IGUub3B0aW9ucywgbyA9IGUuc2VsZWN0ZWRJbmRleCwgYSA9ICJzZWxlY3Qtb25lIiA9PT0gZS50eXBlLCB1ID0gYSA/IG51bGwgOiBbXSwgcyA9IGEgPyBvICsgMSA6IGkubGVuZ3RoOyBmb3IgKHIgPSBvIDwgMCA/IHMgOiBhID8gbyA6IDA7IHIgPCBzOyByKyspaWYgKCgobiA9IGlbcl0pLnNlbGVjdGVkIHx8IHIgPT09IG8pICYmICFuLmRpc2FibGVkICYmICghbi5wYXJlbnROb2RlLmRpc2FibGVkIHx8ICFEKG4ucGFyZW50Tm9kZSwgIm9wdGdyb3VwIikpKSB7IGlmICh0ID0gdyhuKS52YWwoKSwgYSkgcmV0dXJuIHQ7IHUucHVzaCh0KSB9IHJldHVybiB1IH0sIHNldDogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIsIGkgPSBlLm9wdGlvbnMsIG8gPSB3Lm1ha2VBcnJheSh0KSwgYSA9IGkubGVuZ3RoOyB3aGlsZSAoYS0tKSAoKHIgPSBpW2FdKS5zZWxlY3RlZCA9IHcuaW5BcnJheSh3LnZhbEhvb2tzLm9wdGlvbi5nZXQociksIG8pID4gLTEpICYmIChuID0gITApOyByZXR1cm4gbiB8fCAoZS5zZWxlY3RlZEluZGV4ID0gLTEpLCBvIH0gfSB9IH0pLCB3LmVhY2goWyJyYWRpbyIsICJjaGVja2JveCJdLCBmdW5jdGlvbiAoKSB7IHcudmFsSG9va3NbdGhpc10gPSB7IHNldDogZnVuY3Rpb24gKGUsIHQpIHsgaWYgKEFycmF5LmlzQXJyYXkodCkpIHJldHVybiBlLmNoZWNrZWQgPSB3LmluQXJyYXkodyhlKS52YWwoKSwgdCkgPiAtMSB9IH0sIGguY2hlY2tPbiB8fCAody52YWxIb29rc1t0aGlzXS5nZXQgPSBmdW5jdGlvbiAoZSkgeyByZXR1cm4gbnVsbCA9PT0gZS5nZXRBdHRyaWJ1dGUoInZhbHVlIikgPyAib24iIDogZS52YWx1ZSB9KSB9KSwgaC5mb2N1c2luID0gIm9uZm9jdXNpbiIgaW4gZTsgdmFyIGx0ID0gL14oPzpmb2N1c2luZm9jdXN8Zm9jdXNvdXRibHVyKSQvLCBjdCA9IGZ1bmN0aW9uIChlKSB7IGUuc3RvcFByb3BhZ2F0aW9uKCkgfTsgdy5leHRlbmQody5ldmVudCwgeyB0cmlnZ2VyOiBmdW5jdGlvbiAodCwgbiwgaSwgbykgeyB2YXIgYSwgdSwgcywgbCwgYywgZCwgcCwgaCwgeSA9IFtpIHx8IHJdLCBtID0gZi5jYWxsKHQsICJ0eXBlIikgPyB0LnR5cGUgOiB0LCBiID0gZi5jYWxsKHQsICJuYW1lc3BhY2UiKSA/IHQubmFtZXNwYWNlLnNwbGl0KCIuIikgOiBbXTsgaWYgKHUgPSBoID0gcyA9IGkgPSBpIHx8IHIsIDMgIT09IGkubm9kZVR5cGUgJiYgOCAhPT0gaS5ub2RlVHlwZSAmJiAhbHQudGVzdChtICsgdy5ldmVudC50cmlnZ2VyZWQpICYmIChtLmluZGV4T2YoIi4iKSA+IC0xICYmIChtID0gKGIgPSBtLnNwbGl0KCIuIikpLnNoaWZ0KCksIGIuc29ydCgpKSwgYyA9IG0uaW5kZXhPZigiOiIpIDwgMCAmJiAib24iICsgbSwgdCA9IHRbdy5leHBhbmRvXSA/IHQgOiBuZXcgdy5FdmVudChtLCAib2JqZWN0IiA9PSB0eXBlb2YgdCAmJiB0KSwgdC5pc1RyaWdnZXIgPSBvID8gMiA6IDMsIHQubmFtZXNwYWNlID0gYi5qb2luKCIuIiksIHQucm5hbWVzcGFjZSA9IHQubmFtZXNwYWNlID8gbmV3IFJlZ0V4cCgiKF58XFwuKSIgKyBiLmpvaW4oIlxcLig/Oi4qXFwufCkiKSArICIoXFwufCQpIikgOiBudWxsLCB0LnJlc3VsdCA9IHZvaWQgMCwgdC50YXJnZXQgfHwgKHQudGFyZ2V0ID0gaSksIG4gPSBudWxsID09IG4gPyBbdF0gOiB3Lm1ha2VBcnJheShuLCBbdF0pLCBwID0gdy5ldmVudC5zcGVjaWFsW21dIHx8IHt9LCBvIHx8ICFwLnRyaWdnZXIgfHwgITEgIT09IHAudHJpZ2dlci5hcHBseShpLCBuKSkpIHsgaWYgKCFvICYmICFwLm5vQnViYmxlICYmICF2KGkpKSB7IGZvciAobCA9IHAuZGVsZWdhdGVUeXBlIHx8IG0sIGx0LnRlc3QobCArIG0pIHx8ICh1ID0gdS5wYXJlbnROb2RlKTsgdTsgdSA9IHUucGFyZW50Tm9kZSl5LnB1c2godSksIHMgPSB1OyBzID09PSAoaS5vd25lckRvY3VtZW50IHx8IHIpICYmIHkucHVzaChzLmRlZmF1bHRWaWV3IHx8IHMucGFyZW50V2luZG93IHx8IGUpIH0gYSA9IDA7IHdoaWxlICgodSA9IHlbYSsrXSkgJiYgIXQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSkgaCA9IHUsIHQudHlwZSA9IGEgPiAxID8gbCA6IHAuYmluZFR5cGUgfHwgbSwgKGQgPSAoSy5nZXQodSwgImV2ZW50cyIpIHx8IHt9KVt0LnR5cGVdICYmIEsuZ2V0KHUsICJoYW5kbGUiKSkgJiYgZC5hcHBseSh1LCBuKSwgKGQgPSBjICYmIHVbY10pICYmIGQuYXBwbHkgJiYgWSh1KSAmJiAodC5yZXN1bHQgPSBkLmFwcGx5KHUsIG4pLCAhMSA9PT0gdC5yZXN1bHQgJiYgdC5wcmV2ZW50RGVmYXVsdCgpKTsgcmV0dXJuIHQudHlwZSA9IG0sIG8gfHwgdC5pc0RlZmF1bHRQcmV2ZW50ZWQoKSB8fCBwLl9kZWZhdWx0ICYmICExICE9PSBwLl9kZWZhdWx0LmFwcGx5KHkucG9wKCksIG4pIHx8ICFZKGkpIHx8IGMgJiYgZyhpW21dKSAmJiAhdihpKSAmJiAoKHMgPSBpW2NdKSAmJiAoaVtjXSA9IG51bGwpLCB3LmV2ZW50LnRyaWdnZXJlZCA9IG0sIHQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSAmJiBoLmFkZEV2ZW50TGlzdGVuZXIobSwgY3QpLCBpW21dKCksIHQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSAmJiBoLnJlbW92ZUV2ZW50TGlzdGVuZXIobSwgY3QpLCB3LmV2ZW50LnRyaWdnZXJlZCA9IHZvaWQgMCwgcyAmJiAoaVtjXSA9IHMpKSwgdC5yZXN1bHQgfSB9LCBzaW11bGF0ZTogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIgPSB3LmV4dGVuZChuZXcgdy5FdmVudCwgbiwgeyB0eXBlOiBlLCBpc1NpbXVsYXRlZDogITAgfSk7IHcuZXZlbnQudHJpZ2dlcihyLCBudWxsLCB0KSB9IH0pLCB3LmZuLmV4dGVuZCh7IHRyaWdnZXI6IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24gKCkgeyB3LmV2ZW50LnRyaWdnZXIoZSwgdCwgdGhpcykgfSkgfSwgdHJpZ2dlckhhbmRsZXI6IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuID0gdGhpc1swXTsgaWYgKG4pIHJldHVybiB3LmV2ZW50LnRyaWdnZXIoZSwgdCwgbiwgITApIH0gfSksIGguZm9jdXNpbiB8fCB3LmVhY2goeyBmb2N1czogImZvY3VzaW4iLCBibHVyOiAiZm9jdXNvdXQiIH0sIGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuID0gZnVuY3Rpb24gKGUpIHsgdy5ldmVudC5zaW11bGF0ZSh0LCBlLnRhcmdldCwgdy5ldmVudC5maXgoZSkpIH07IHcuZXZlbnQuc3BlY2lhbFt0XSA9IHsgc2V0dXA6IGZ1bmN0aW9uICgpIHsgdmFyIHIgPSB0aGlzLm93bmVyRG9jdW1lbnQgfHwgdGhpcywgaSA9IEsuYWNjZXNzKHIsIHQpOyBpIHx8IHIuYWRkRXZlbnRMaXN0ZW5lcihlLCBuLCAhMCksIEsuYWNjZXNzKHIsIHQsIChpIHx8IDApICsgMSkgfSwgdGVhcmRvd246IGZ1bmN0aW9uICgpIHsgdmFyIHIgPSB0aGlzLm93bmVyRG9jdW1lbnQgfHwgdGhpcywgaSA9IEsuYWNjZXNzKHIsIHQpIC0gMTsgaSA/IEsuYWNjZXNzKHIsIHQsIGkpIDogKHIucmVtb3ZlRXZlbnRMaXN0ZW5lcihlLCBuLCAhMCksIEsucmVtb3ZlKHIsIHQpKSB9IH0gfSk7IHZhciBmdCA9IC9cW1xdJC8sIGR0ID0gL1xyP1xuL2csIHB0ID0gL14oPzpzdWJtaXR8YnV0dG9ufGltYWdlfHJlc2V0fGZpbGUpJC9pLCBodCA9IC9eKD86aW5wdXR8c2VsZWN0fHRleHRhcmVhfGtleWdlbikvaTsgZnVuY3Rpb24gZ3QoZSwgdCwgbiwgcikgeyB2YXIgaTsgaWYgKEFycmF5LmlzQXJyYXkodCkpIHcuZWFjaCh0LCBmdW5jdGlvbiAodCwgaSkgeyBuIHx8IGZ0LnRlc3QoZSkgPyByKGUsIGkpIDogZ3QoZSArICJbIiArICgib2JqZWN0IiA9PSB0eXBlb2YgaSAmJiBudWxsICE9IGkgPyB0IDogIiIpICsgIl0iLCBpLCBuLCByKSB9KTsgZWxzZSBpZiAobiB8fCAib2JqZWN0IiAhPT0gYih0KSkgcihlLCB0KTsgZWxzZSBmb3IgKGkgaW4gdCkgZ3QoZSArICJbIiArIGkgKyAiXSIsIHRbaV0sIG4sIHIpIH0gdy5wYXJhbSA9IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCByID0gW10sIGkgPSBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IGcodCkgPyB0KCkgOiB0OyByW3IubGVuZ3RoXSA9IGVuY29kZVVSSUNvbXBvbmVudChlKSArICI9IiArIGVuY29kZVVSSUNvbXBvbmVudChudWxsID09IG4gPyAiIiA6IG4pIH07IGlmIChBcnJheS5pc0FycmF5KGUpIHx8IGUuanF1ZXJ5ICYmICF3LmlzUGxhaW5PYmplY3QoZSkpIHcuZWFjaChlLCBmdW5jdGlvbiAoKSB7IGkodGhpcy5uYW1lLCB0aGlzLnZhbHVlKSB9KTsgZWxzZSBmb3IgKG4gaW4gZSkgZ3QobiwgZVtuXSwgdCwgaSk7IHJldHVybiByLmpvaW4oIiYiKSB9LCB3LmZuLmV4dGVuZCh7IHNlcmlhbGl6ZTogZnVuY3Rpb24gKCkgeyByZXR1cm4gdy5wYXJhbSh0aGlzLnNlcmlhbGl6ZUFycmF5KCkpIH0sIHNlcmlhbGl6ZUFycmF5OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLm1hcChmdW5jdGlvbiAoKSB7IHZhciBlID0gdy5wcm9wKHRoaXMsICJlbGVtZW50cyIpOyByZXR1cm4gZSA/IHcubWFrZUFycmF5KGUpIDogdGhpcyB9KS5maWx0ZXIoZnVuY3Rpb24gKCkgeyB2YXIgZSA9IHRoaXMudHlwZTsgcmV0dXJuIHRoaXMubmFtZSAmJiAhdyh0aGlzKS5pcygiOmRpc2FibGVkIikgJiYgaHQudGVzdCh0aGlzLm5vZGVOYW1lKSAmJiAhcHQudGVzdChlKSAmJiAodGhpcy5jaGVja2VkIHx8ICFkZS50ZXN0KGUpKSB9KS5tYXAoZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4gPSB3KHRoaXMpLnZhbCgpOyByZXR1cm4gbnVsbCA9PSBuID8gbnVsbCA6IEFycmF5LmlzQXJyYXkobikgPyB3Lm1hcChuLCBmdW5jdGlvbiAoZSkgeyByZXR1cm4geyBuYW1lOiB0Lm5hbWUsIHZhbHVlOiBlLnJlcGxhY2UoZHQsICJcclxuIikgfSB9KSA6IHsgbmFtZTogdC5uYW1lLCB2YWx1ZTogbi5yZXBsYWNlKGR0LCAiXHJcbiIpIH0gfSkuZ2V0KCkgfSB9KSwgdy5mbi5leHRlbmQoeyB3cmFwQWxsOiBmdW5jdGlvbiAoZSkgeyB2YXIgdDsgcmV0dXJuIHRoaXNbMF0gJiYgKGcoZSkgJiYgKGUgPSBlLmNhbGwodGhpc1swXSkpLCB0ID0gdyhlLCB0aGlzWzBdLm93bmVyRG9jdW1lbnQpLmVxKDApLmNsb25lKCEwKSwgdGhpc1swXS5wYXJlbnROb2RlICYmIHQuaW5zZXJ0QmVmb3JlKHRoaXNbMF0pLCB0Lm1hcChmdW5jdGlvbiAoKSB7IHZhciBlID0gdGhpczsgd2hpbGUgKGUuZmlyc3RFbGVtZW50Q2hpbGQpIGUgPSBlLmZpcnN0RWxlbWVudENoaWxkOyByZXR1cm4gZSB9KS5hcHBlbmQodGhpcykpLCB0aGlzIH0sIHdyYXBJbm5lcjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGcoZSkgPyB0aGlzLmVhY2goZnVuY3Rpb24gKHQpIHsgdyh0aGlzKS53cmFwSW5uZXIoZS5jYWxsKHRoaXMsIHQpKSB9KSA6IHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7IHZhciB0ID0gdyh0aGlzKSwgbiA9IHQuY29udGVudHMoKTsgbi5sZW5ndGggPyBuLndyYXBBbGwoZSkgOiB0LmFwcGVuZChlKSB9KSB9LCB3cmFwOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGcoZSk7IHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24gKG4pIHsgdyh0aGlzKS53cmFwQWxsKHQgPyBlLmNhbGwodGhpcywgbikgOiBlKSB9KSB9LCB1bndyYXA6IGZ1bmN0aW9uIChlKSB7IHJldHVybiB0aGlzLnBhcmVudChlKS5ub3QoImJvZHkiKS5lYWNoKGZ1bmN0aW9uICgpIHsgdyh0aGlzKS5yZXBsYWNlV2l0aCh0aGlzLmNoaWxkTm9kZXMpIH0pLCB0aGlzIH0gfSksIHcuZXhwci5wc2V1ZG9zLmhpZGRlbiA9IGZ1bmN0aW9uIChlKSB7IHJldHVybiAhdy5leHByLnBzZXVkb3MudmlzaWJsZShlKSB9LCB3LmV4cHIucHNldWRvcy52aXNpYmxlID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuICEhKGUub2Zmc2V0V2lkdGggfHwgZS5vZmZzZXRIZWlnaHQgfHwgZS5nZXRDbGllbnRSZWN0cygpLmxlbmd0aCkgfSwgaC5jcmVhdGVIVE1MRG9jdW1lbnQgPSBmdW5jdGlvbiAoKSB7IHZhciBlID0gci5pbXBsZW1lbnRhdGlvbi5jcmVhdGVIVE1MRG9jdW1lbnQoIiIpLmJvZHk7IHJldHVybiBlLmlubmVySFRNTCA9ICI8Zm9ybT48L2Zvcm0+PGZvcm0+PC9mb3JtPiIsIDIgPT09IGUuY2hpbGROb2Rlcy5sZW5ndGggfSgpLCB3LnBhcnNlSFRNTCA9IGZ1bmN0aW9uIChlLCB0LCBuKSB7IGlmICgic3RyaW5nIiAhPSB0eXBlb2YgZSkgcmV0dXJuIFtdOyAiYm9vbGVhbiIgPT0gdHlwZW9mIHQgJiYgKG4gPSB0LCB0ID0gITEpOyB2YXIgaSwgbywgYTsgcmV0dXJuIHQgfHwgKGguY3JlYXRlSFRNTERvY3VtZW50ID8gKChpID0gKHQgPSByLmltcGxlbWVudGF0aW9uLmNyZWF0ZUhUTUxEb2N1bWVudCgiIikpLmNyZWF0ZUVsZW1lbnQoImJhc2UiKSkuaHJlZiA9IHIubG9jYXRpb24uaHJlZiwgdC5oZWFkLmFwcGVuZENoaWxkKGkpKSA6IHQgPSByKSwgbyA9IFMuZXhlYyhlKSwgYSA9ICFuICYmIFtdLCBvID8gW3QuY3JlYXRlRWxlbWVudChvWzFdKV0gOiAobyA9IGJlKFtlXSwgdCwgYSksIGEgJiYgYS5sZW5ndGggJiYgdyhhKS5yZW1vdmUoKSwgdy5tZXJnZShbXSwgby5jaGlsZE5vZGVzKSkgfSwgdy5vZmZzZXQgPSB7IHNldE9mZnNldDogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIsIGksIG8sIGEsIHUsIHMsIGwsIGMgPSB3LmNzcyhlLCAicG9zaXRpb24iKSwgZiA9IHcoZSksIGQgPSB7fTsgInN0YXRpYyIgPT09IGMgJiYgKGUuc3R5bGUucG9zaXRpb24gPSAicmVsYXRpdmUiKSwgdSA9IGYub2Zmc2V0KCksIG8gPSB3LmNzcyhlLCAidG9wIiksIHMgPSB3LmNzcyhlLCAibGVmdCIpLCAobCA9ICgiYWJzb2x1dGUiID09PSBjIHx8ICJmaXhlZCIgPT09IGMpICYmIChvICsgcykuaW5kZXhPZigiYXV0byIpID4gLTEpID8gKGEgPSAociA9IGYucG9zaXRpb24oKSkudG9wLCBpID0gci5sZWZ0KSA6IChhID0gcGFyc2VGbG9hdChvKSB8fCAwLCBpID0gcGFyc2VGbG9hdChzKSB8fCAwKSwgZyh0KSAmJiAodCA9IHQuY2FsbChlLCBuLCB3LmV4dGVuZCh7fSwgdSkpKSwgbnVsbCAhPSB0LnRvcCAmJiAoZC50b3AgPSB0LnRvcCAtIHUudG9wICsgYSksIG51bGwgIT0gdC5sZWZ0ICYmIChkLmxlZnQgPSB0LmxlZnQgLSB1LmxlZnQgKyBpKSwgInVzaW5nIiBpbiB0ID8gdC51c2luZy5jYWxsKGUsIGQpIDogZi5jc3MoZCkgfSB9LCB3LmZuLmV4dGVuZCh7IG9mZnNldDogZnVuY3Rpb24gKGUpIHsgaWYgKGFyZ3VtZW50cy5sZW5ndGgpIHJldHVybiB2b2lkIDAgPT09IGUgPyB0aGlzIDogdGhpcy5lYWNoKGZ1bmN0aW9uICh0KSB7IHcub2Zmc2V0LnNldE9mZnNldCh0aGlzLCBlLCB0KSB9KTsgdmFyIHQsIG4sIHIgPSB0aGlzWzBdOyBpZiAocikgcmV0dXJuIHIuZ2V0Q2xpZW50UmVjdHMoKS5sZW5ndGggPyAodCA9IHIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksIG4gPSByLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcsIHsgdG9wOiB0LnRvcCArIG4ucGFnZVlPZmZzZXQsIGxlZnQ6IHQubGVmdCArIG4ucGFnZVhPZmZzZXQgfSkgOiB7IHRvcDogMCwgbGVmdDogMCB9IH0sIHBvc2l0aW9uOiBmdW5jdGlvbiAoKSB7IGlmICh0aGlzWzBdKSB7IHZhciBlLCB0LCBuLCByID0gdGhpc1swXSwgaSA9IHsgdG9wOiAwLCBsZWZ0OiAwIH07IGlmICgiZml4ZWQiID09PSB3LmNzcyhyLCAicG9zaXRpb24iKSkgdCA9IHIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7IGVsc2UgeyB0ID0gdGhpcy5vZmZzZXQoKSwgbiA9IHIub3duZXJEb2N1bWVudCwgZSA9IHIub2Zmc2V0UGFyZW50IHx8IG4uZG9jdW1lbnRFbGVtZW50OyB3aGlsZSAoZSAmJiAoZSA9PT0gbi5ib2R5IHx8IGUgPT09IG4uZG9jdW1lbnRFbGVtZW50KSAmJiAic3RhdGljIiA9PT0gdy5jc3MoZSwgInBvc2l0aW9uIikpIGUgPSBlLnBhcmVudE5vZGU7IGUgJiYgZSAhPT0gciAmJiAxID09PSBlLm5vZGVUeXBlICYmICgoaSA9IHcoZSkub2Zmc2V0KCkpLnRvcCArPSB3LmNzcyhlLCAiYm9yZGVyVG9wV2lkdGgiLCAhMCksIGkubGVmdCArPSB3LmNzcyhlLCAiYm9yZGVyTGVmdFdpZHRoIiwgITApKSB9IHJldHVybiB7IHRvcDogdC50b3AgLSBpLnRvcCAtIHcuY3NzKHIsICJtYXJnaW5Ub3AiLCAhMCksIGxlZnQ6IHQubGVmdCAtIGkubGVmdCAtIHcuY3NzKHIsICJtYXJnaW5MZWZ0IiwgITApIH0gfSB9LCBvZmZzZXRQYXJlbnQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMubWFwKGZ1bmN0aW9uICgpIHsgdmFyIGUgPSB0aGlzLm9mZnNldFBhcmVudDsgd2hpbGUgKGUgJiYgInN0YXRpYyIgPT09IHcuY3NzKGUsICJwb3NpdGlvbiIpKSBlID0gZS5vZmZzZXRQYXJlbnQ7IHJldHVybiBlIHx8IHhlIH0pIH0gfSksIHcuZWFjaCh7IHNjcm9sbExlZnQ6ICJwYWdlWE9mZnNldCIsIHNjcm9sbFRvcDogInBhZ2VZT2Zmc2V0IiB9LCBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9ICJwYWdlWU9mZnNldCIgPT09IHQ7IHcuZm5bZV0gPSBmdW5jdGlvbiAocikgeyByZXR1cm4gXyh0aGlzLCBmdW5jdGlvbiAoZSwgciwgaSkgeyB2YXIgbzsgaWYgKHYoZSkgPyBvID0gZSA6IDkgPT09IGUubm9kZVR5cGUgJiYgKG8gPSBlLmRlZmF1bHRWaWV3KSwgdm9pZCAwID09PSBpKSByZXR1cm4gbyA/IG9bdF0gOiBlW3JdOyBvID8gby5zY3JvbGxUbyhuID8gby5wYWdlWE9mZnNldCA6IGksIG4gPyBpIDogby5wYWdlWU9mZnNldCkgOiBlW3JdID0gaSB9LCBlLCByLCBhcmd1bWVudHMubGVuZ3RoKSB9IH0pLCB3LmVhY2goWyJ0b3AiLCAibGVmdCJdLCBmdW5jdGlvbiAoZSwgdCkgeyB3LmNzc0hvb2tzW3RdID0gemUoaC5waXhlbFBvc2l0aW9uLCBmdW5jdGlvbiAoZSwgbikgeyBpZiAobikgcmV0dXJuIG4gPSBGZShlLCB0KSwgTWUudGVzdChuKSA/IHcoZSkucG9zaXRpb24oKVt0XSArICJweCIgOiBuIH0pIH0pLCB3LmVhY2goeyBIZWlnaHQ6ICJoZWlnaHQiLCBXaWR0aDogIndpZHRoIiB9LCBmdW5jdGlvbiAoZSwgdCkgeyB3LmVhY2goeyBwYWRkaW5nOiAiaW5uZXIiICsgZSwgY29udGVudDogdCwgIiI6ICJvdXRlciIgKyBlIH0sIGZ1bmN0aW9uIChuLCByKSB7IHcuZm5bcl0gPSBmdW5jdGlvbiAoaSwgbykgeyB2YXIgYSA9IGFyZ3VtZW50cy5sZW5ndGggJiYgKG4gfHwgImJvb2xlYW4iICE9IHR5cGVvZiBpKSwgdSA9IG4gfHwgKCEwID09PSBpIHx8ICEwID09PSBvID8gIm1hcmdpbiIgOiAiYm9yZGVyIik7IHJldHVybiBfKHRoaXMsIGZ1bmN0aW9uICh0LCBuLCBpKSB7IHZhciBvOyByZXR1cm4gdih0KSA/IDAgPT09IHIuaW5kZXhPZigib3V0ZXIiKSA/IHRbImlubmVyIiArIGVdIDogdC5kb2N1bWVudC5kb2N1bWVudEVsZW1lbnRbImNsaWVudCIgKyBlXSA6IDkgPT09IHQubm9kZVR5cGUgPyAobyA9IHQuZG9jdW1lbnRFbGVtZW50LCBNYXRoLm1heCh0LmJvZHlbInNjcm9sbCIgKyBlXSwgb1sic2Nyb2xsIiArIGVdLCB0LmJvZHlbIm9mZnNldCIgKyBlXSwgb1sib2Zmc2V0IiArIGVdLCBvWyJjbGllbnQiICsgZV0pKSA6IHZvaWQgMCA9PT0gaSA/IHcuY3NzKHQsIG4sIHUpIDogdy5zdHlsZSh0LCBuLCBpLCB1KSB9LCB0LCBhID8gaSA6IHZvaWQgMCwgYSkgfSB9KSB9KSwgdy5lYWNoKCJibHVyIGZvY3VzIGZvY3VzaW4gZm9jdXNvdXQgcmVzaXplIHNjcm9sbCBjbGljayBkYmxjbGljayBtb3VzZWRvd24gbW91c2V1cCBtb3VzZW1vdmUgbW91c2VvdmVyIG1vdXNlb3V0IG1vdXNlZW50ZXIgbW91c2VsZWF2ZSBjaGFuZ2Ugc2VsZWN0IHN1Ym1pdCBrZXlkb3duIGtleXByZXNzIGtleXVwIGNvbnRleHRtZW51Ii5zcGxpdCgiICIpLCBmdW5jdGlvbiAoZSwgdCkgeyB3LmZuW3RdID0gZnVuY3Rpb24gKGUsIG4pIHsgcmV0dXJuIGFyZ3VtZW50cy5sZW5ndGggPiAwID8gdGhpcy5vbih0LCBudWxsLCBlLCBuKSA6IHRoaXMudHJpZ2dlcih0KSB9IH0pLCB3LmZuLmV4dGVuZCh7IGhvdmVyOiBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gdGhpcy5tb3VzZWVudGVyKGUpLm1vdXNlbGVhdmUodCB8fCBlKSB9IH0pLCB3LmZuLmV4dGVuZCh7IGJpbmQ6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiB0aGlzLm9uKGUsIG51bGwsIHQsIG4pIH0sIHVuYmluZDogZnVuY3Rpb24gKGUsIHQpIHsgcmV0dXJuIHRoaXMub2ZmKGUsIG51bGwsIHQpIH0sIGRlbGVnYXRlOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyByZXR1cm4gdGhpcy5vbih0LCBlLCBuLCByKSB9LCB1bmRlbGVnYXRlOiBmdW5jdGlvbiAoZSwgdCwgbikgeyByZXR1cm4gMSA9PT0gYXJndW1lbnRzLmxlbmd0aCA/IHRoaXMub2ZmKGUsICIqKiIpIDogdGhpcy5vZmYodCwgZSB8fCAiKioiLCBuKSB9IH0pLCB3LnByb3h5ID0gZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIsIGk7IGlmICgic3RyaW5nIiA9PSB0eXBlb2YgdCAmJiAobiA9IGVbdF0sIHQgPSBlLCBlID0gbiksIGcoZSkpIHJldHVybiByID0gby5jYWxsKGFyZ3VtZW50cywgMiksIGkgPSBmdW5jdGlvbiAoKSB7IHJldHVybiBlLmFwcGx5KHQgfHwgdGhpcywgci5jb25jYXQoby5jYWxsKGFyZ3VtZW50cykpKSB9LCBpLmd1aWQgPSBlLmd1aWQgPSBlLmd1aWQgfHwgdy5ndWlkKysgLCBpIH0sIHcuaG9sZFJlYWR5ID0gZnVuY3Rpb24gKGUpIHsgZSA/IHcucmVhZHlXYWl0KysgOiB3LnJlYWR5KCEwKSB9LCB3LmlzQXJyYXkgPSBBcnJheS5pc0FycmF5LCB3LnBhcnNlSlNPTiA9IEpTT04ucGFyc2UsIHcubm9kZU5hbWUgPSBELCB3LmlzRnVuY3Rpb24gPSBnLCB3LmlzV2luZG93ID0gdiwgdy5jYW1lbENhc2UgPSBRLCB3LnR5cGUgPSBiLCB3Lm5vdyA9IERhdGUubm93LCB3LmlzTnVtZXJpYyA9IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gdy50eXBlKGUpOyByZXR1cm4gKCJudW1iZXIiID09PSB0IHx8ICJzdHJpbmciID09PSB0KSAmJiAhaXNOYU4oZSAtIHBhcnNlRmxvYXQoZSkpIH0sICJmdW5jdGlvbiIgPT0gdHlwZW9mIGRlZmluZSAmJiBkZWZpbmUuYW1kICYmIGRlZmluZSgianF1ZXJ5IiwgW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHcgfSk7IHZhciB2dCA9IGUualF1ZXJ5LCB5dCA9IGUuJDsgcmV0dXJuIHcubm9Db25mbGljdCA9IGZ1bmN0aW9uICh0KSB7IHJldHVybiBlLiQgPT09IHcgJiYgKGUuJCA9IHl0KSwgdCAmJiBlLmpRdWVyeSA9PT0gdyAmJiAoZS5qUXVlcnkgPSB2dCksIHcgfSwgdCB8fCAoZS5qUXVlcnkgPSBlLiQgPSB3KSwgdyB9KTs=\"") + packr.PackJSONBytes("./assets/default", "wails.js", "\"Ly8gV2FpbHMgcnVudGltZSBKUwoKKGZ1bmN0aW9uICgpIHsKCXdpbmRvdy53YWlscyA9IHdpbmRvdy53YWlscyB8fCB7CgkJJDoge30KCX07CgoJLyoqKioqKioqKioqKioqKioqKiBVdGlsaXR5IEZ1bmN0aW9ucyAqKioqKioqKioqKioqKioqKioqKioqKiovCgoJLy8gLS0tLS0tLS0tLS0tLS0gUmFuZG9tIC0tLS0tLS0tLS0tLS0tCgkvLyBBd2Vzb21lUmFuZG9tCglmdW5jdGlvbiBjcnlwdG9SYW5kb20oKSB7CgkJdmFyIGFycmF5ID0gbmV3IFVpbnQzMkFycmF5KDEpOwoJCXJldHVybiB3aW5kb3cuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhhcnJheSlbMF07Cgl9CgoJLy8gTE9MUmFuZG9tCglmdW5jdGlvbiBiYXNpY1JhbmRvbSgpIHsKCQlyZXR1cm4gTWF0aC5yYW5kb20oKSAqIDkwMDcxOTkyNTQ3NDA5OTE7Cgl9CgoJLy8gUGljayBvbmUgYmFzZWQgb24gYnJvd3NlciBjYXBhYmlsaXR5Cgl2YXIgcmFuZG9tRnVuYzsKCWlmICh3aW5kb3cuY3J5cHRvKSB7CgkJcmFuZG9tRnVuYyA9IGNyeXB0b1JhbmRvbTsKCX0gZWxzZSB7CgkJcmFuZG9tRnVuYyA9IGJhc2ljUmFuZG9tOwoJfQoKCS8vIC0tLS0tLS0tLS0tLS0tIElkZW50aWZpZXJzIC0tLS0tLS0tLS0tLS0tLQoKCWZ1bmN0aW9uIGlzVmFsaWRJZGVudGlmaWVyKG5hbWUpIHsKCQkvLyBEb24ndCB4c3MgeW91cnNlbGYgOi0pCgkJdHJ5IHsKCQkJbmV3IEZ1bmN0aW9uKCJ2YXIgIiArIG5hbWUpOwoJCQlyZXR1cm4gdHJ1ZQoJCX0gY2F0Y2ggKGUpIHsKCQkJcmV0dXJuIGZhbHNlCgkJfQoJfQoKCS8vIC0tLS0tLS0tLS0tLS0tIEpTIC0tLS0tLS0tLS0tLS0tLS0KCWZ1bmN0aW9uIGFkZFNjcmlwdChqcywgY2FsbGJhY2tJRCkgewoJCWNvbnNvbGUubG9nKCJBZGRpbmcgc2NyaXB0OiAiICsganMpCgkJdmFyIHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInNjcmlwdCIpOwoJCXNjcmlwdC50ZXh0ID0ganM7CgkJZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChzY3JpcHQpOwoJCWNvbnNvbGUubG9nKCJDYWxsaW5nIGJhY2sgd2l0aDoiICsgY2FsbGJhY2tJRCk7CgkJd2luZG93LndhaWxzLmV2ZW50cy5lbWl0KGNhbGxiYWNrSUQpOwoJfQoKCS8vIC0tLS0tLS0tLS0tLS0tIEhUTUwgLS0tLS0tLS0tLS0tLS0KCWZ1bmN0aW9uIHNldERvY3VtZW50KGh0bWwpIHsKCQlkb2N1bWVudC5vcGVuKCk7CgkJZG9jdW1lbnQud3JpdGUoaHRtbCk7CgkJZG9jdW1lbnQuY2xvc2UoKTsKCX0KCgkvLyAtLS0tLS0tLS0tLS0tLSBDU1MgLS0tLS0tLS0tLS0tLS0tCgkvLyBBZGFwdGVkIGZyb20gd2VidmlldyAtIHRoYW5rcyB6c2VyZ2UhCglmdW5jdGlvbiBpbmplY3RDU1MoY3NzKSB7CgkJdmFyIGVsZW0gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzdHlsZScpOwoJCWVsZW0uc2V0QXR0cmlidXRlKCd0eXBlJywgJ3RleHQvY3NzJyk7CgkJaWYgKGVsZW0uc3R5bGVTaGVldCkgewoJCQllbGVtLnN0eWxlU2hlZXQuY3NzVGV4dCA9IGNzczsKCQl9IGVsc2UgewoJCQllbGVtLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGNzcykpOwoJCX0KCQl2YXIgaGVhZCA9IGRvY3VtZW50LmhlYWQgfHwgZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2hlYWQnKVswXTsKCQloZWFkLmFwcGVuZENoaWxkKGVsZW0pCgl9CgoJLyoqKioqKioqKioqKioqKioqKioqKioqKiogQmluZGluZ3MgKioqKioqKioqKioqKioqKioqKioqKioqKi8KCgl2YXIgYmluZGluZ3NCYXNlUGF0aCA9IHdpbmRvdy53YWlscy4kOwoKCS8vIENyZWF0ZXMgdGhlIHBhdGggZ2l2ZW4gaW4gdGhlIGJpbmRpbmdzIHBhdGgKCWZ1bmN0aW9uIGFkZEJpbmRpbmdQYXRoKHBhdGhTZWN0aW9ucykgewoJCS8vIFN0YXJ0IGF0IHRoZSBiYXNlIHBhdGgKCQl2YXIgY3VycmVudFBhdGggPSBiaW5kaW5nc0Jhc2VQYXRoCgkJLy8gZm9yIGVhY2ggc2VjdGlvbiBvZiB0aGUgZ2l2ZW4gcGF0aAoJCWZvciAodmFyIHNlY3Rpb24gb2YgcGF0aFNlY3Rpb25zKSB7CgoJCQkvLyBJcyBzZWN0aW9uIGEgdmFsaWQgamF2YXNjcmlwdCBpZGVudGlmaWVyPwoJCQlpZiAoIWlzVmFsaWRJZGVudGlmaWVyKHNlY3Rpb24pKSB7CgkJCQl2YXIgZXJyTWVzc2FnZSA9IHNlY3Rpb24gKyAiIGlzIG5vdCBhIHZhbGlkIGphdmFzY3JpcHQgaWRlbnRpZmllci4iCgkJCQl2YXIgZXJyID0gbmV3IEVycm9yKGVyck1lc3NhZ2UpCgkJCQlyZXR1cm4gW251bGwsIGVycl0KCQkJfQoKCQkJLy8gQWRkIGlmIGRvZXNuJ3QgZXhpc3QKCQkJaWYgKCFjdXJyZW50UGF0aFtzZWN0aW9uXSkgewoJCQkJY3VycmVudFBhdGhbc2VjdGlvbl0gPSB7fQoJCQl9CgkJCS8vIHVwZGF0ZSBjdXJyZW50IHBhdGggdG8gbmV3IHBhdGgKCQkJY3VycmVudFBhdGggPSBjdXJyZW50UGF0aFtzZWN0aW9uXQoJCX0KCQlyZXR1cm4gW2N1cnJlbnRQYXRoLCBudWxsXQoJfQoKCWZ1bmN0aW9uIG5ld0JpbmRpbmcoYmluZGluZ05hbWUpIHsKCgkJLy8gR2V0IGFsbCB0aGUgc2VjdGlvbnMgb2YgdGhlIGJpbmRpbmcKCQl2YXIgYmluZGluZ1NlY3Rpb25zID0gYmluZGluZ05hbWUuc3BsaXQoJy4nKTsKCgkJLy8gR2V0IHRoZSBhY3R1YWwgZnVuY3Rpb24vbWV0aG9kIGNhbGwgbmFtZQoJCXZhciBjYWxsTmFtZSA9IGJpbmRpbmdTZWN0aW9ucy5wb3AoKTsKCgkJLy8gQWRkIHBhdGggdG8gYmluZGluZwoJCVtwYXRoVG9CaW5kaW5nLCBlcnJdID0gYWRkQmluZGluZ1BhdGgoYmluZGluZ1NlY3Rpb25zKQoKCQlpZiAoZXJyICE9IG51bGwpIHsKCQkJLy8gV2UgbmVlZCB0byByZXR1cm4gYW4gZXJyb3IKCQkJLy8gd2luZG93LndhaWxzLmxvZy5FcnJvcigiIikKCQkJcmV0dXJuCgkJfQoKCQkvLyBBZGQgYmluZGluZyBjYWxsCgkJcGF0aFRvQmluZGluZ1tjYWxsTmFtZV0gPSBmdW5jdGlvbiAoKSB7CgoJCQkvLyBObyB0aW1lb3V0IGJ5IGRlZmF1bHQKCQkJdmFyIHRpbWVvdXQgPSAwOwoKCQkJLy8gQWN0dWFsIGZ1bmN0aW9uCgkJCWZ1bmN0aW9uIGR5bmFtaWMoKSB7CgkJCQl2YXIgYXJncyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKQoJCQkJcmV0dXJuIGNhbGwoYmluZGluZ05hbWUsIGFyZ3MsIHRpbWVvdXQpOwoJCQl9CgoJCQkvLyBBbGxvdyBzZXR0aW5nIHRpbWVvdXQgdG8gZnVuY3Rpb24KCQkJZHluYW1pYy5zZXRUaW1lb3V0ID0gZnVuY3Rpb24gKG5ld1RpbWVvdXQpIHsKCQkJCXRpbWVvdXQgPSBuZXdUaW1lb3V0OwoJCQl9CgoJCQkvLyBBbGxvdyBnZXR0aW5nIHRpbWVvdXQgdG8gZnVuY3Rpb24KCQkJZHluYW1pYy5nZXRUaW1lb3V0ID0gZnVuY3Rpb24gKCkgewoJCQkJcmV0dXJuIHRpbWVvdXQ7CgkJCX0KCgkJCXJldHVybiBkeW5hbWljOwoJCX0oKTsKCX0KCgkvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKCS8qKioqKioqKioqKioqKioqKioqKioqKioqKiogQ2FsbHMgKioqKioqKioqKioqKioqKioqKioqKioqKiovCgoJdmFyIGNhbGxiYWNrcyA9IHt9OwoKCS8vIENhbGwgc2VuZHMgYSBtZXNzYWdlIHRvIHRoZSBiYWNrZW5kIHRvIGNhbGwgdGhlIGJpbmRpbmcgd2l0aCB0aGUKCS8vIGdpdmVuIGRhdGEuIEEgcHJvbWlzZSBpcyByZXR1cm5lZCBhbmQgd2lsbCBiZSBjb21wbGV0ZWQgd2hlbiB0aGUKCS8vIGJhY2tlbmQgcmVzcG9uZHMuIFRoaXMgd2lsbCBiZSByZXNvbHZlZCB3aGVuIHRoZSBjYWxsIHdhcyBzdWNjZXNzZnVsCgkvLyBvciByZWplY3RlZCBpZiBhbiBlcnJvciBpcyBwYXNzZWQgYmFjay4KCS8vIFRoZXJlIGlzIGEgdGltZW91dCBtZWNoYW5pc20uIElmIHRoZSBjYWxsIGRvZXNuJ3QgcmVzcG9uZCBpbiB0aGUgZ2l2ZW4KCS8vIHRpbWUgKGluIG1pbGxpc2Vjb25kcykgdGhlbiB0aGUgcHJvbWlzZSBpcyByZWplY3RlZC4KCglmdW5jdGlvbiBjYWxsKGJpbmRpbmdOYW1lLCBkYXRhLCB0aW1lb3V0KSB7CgoJCS8vIFRpbWVvdXQgaW5maW5pdGUgYnkgZGVmYXVsdAoJCWlmICh0aW1lb3V0ID09IG51bGwgfHwgdGltZW91dCA9PSB1bmRlZmluZWQpIHsKCQkJdGltZW91dCA9IDA7CgkJfQoKCQkvLyBDcmVhdGUgYSBwcm9taXNlCgkJcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHsKCgkJCS8vIENyZWF0ZSBhIHVuaXF1ZSBjYWxsYmFja0lECgkJCXZhciBjYWxsYmFja0lEOwoJCQlkbyB7CgkJCQljYWxsYmFja0lEID0gYmluZGluZ05hbWUgKyAiLSIgKyByYW5kb21GdW5jKCk7CgkJCX0gd2hpbGUgKGNhbGxiYWNrc1tjYWxsYmFja0lEXSkKCgkJCS8vIFNldCB0aW1lb3V0CgkJCWlmICh0aW1lb3V0ID4gMCkgewoJCQkJdmFyIHRpbWVvdXRIYW5kbGUgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHsKCQkJCQlyZWplY3QoRXJyb3IoIkNhbGwgdG8gIiArIGJpbmRpbmdOYW1lICsgIiB0aW1lZCBvdXQuIFJlcXVlc3QgSUQ6ICIgKyBjYWxsYmFja0lEKSkKCQkJCX0sIHRpbWVvdXQpOwoJCQl9CgoJCQkvLyBTdG9yZSBjYWxsYmFjawoJCQljYWxsYmFja3NbY2FsbGJhY2tJRF0gPSB7CgkJCQl0aW1lb3V0SGFuZGxlOiB0aW1lb3V0SGFuZGxlLAoJCQkJcmVqZWN0OiByZWplY3QsCgkJCQlyZXNvbHZlOiByZXNvbHZlCgkJCX0KCQkJdHJ5IHsKCQkJCXZhciBwYXlsb2FkZGF0YSA9IEpTT04uc3RyaW5naWZ5KGRhdGEpCgkJCQkvLyBDcmVhdGUgdGhlIG1lc3NhZ2UKCQkJCW1lc3NhZ2UgPSB7CgkJCQkJdHlwZTogImNhbGwiLAoJCQkJCWNhbGxiYWNraWQ6IGNhbGxiYWNrSUQsCgkJCQkJcGF5bG9hZDogewoJCQkJCQliaW5kaW5nTmFtZTogYmluZGluZ05hbWUsCgkJCQkJCWRhdGE6IHBheWxvYWRkYXRhLAoJCQkJCX0KCQkJCX0KCgkJCQkvLyBNYWtlIHRoZSBjYWxsCgkJCQl2YXIgcGF5bG9hZCA9IEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpCgkJCQlleHRlcm5hbC5pbnZva2UocGF5bG9hZCk7CgkJCX0gY2F0Y2ggKGUpIHsKCQkJCWNvbnNvbGUuZXJyb3IoZSkKCQkJfQoJCX0pCgl9CgoKCS8vIENhbGxlZCBieSB0aGUgYmFja2VuZCB0byByZXR1cm4gZGF0YSB0byBhIHByZXZpb3VzbHkgY2FsbGVkCgkvLyBiaW5kaW5nIGludm9jYXRpb24KCWZ1bmN0aW9uIGNhbGxiYWNrKGluY29taW5nTWVzc2FnZSkgewoJCS8vIHdhaWxzLmxvZy5kZWJ1ZygiY2FsbGJhY2sgY2FsbGVkIHdpdGg6ICIgKyBpbmNvbWluZ01lc3NhZ2UpCgkJLy8gUGFyc2UgdGhlIG1lc3NhZ2UKCQl2YXIgbWVzc2FnZQoJCS8vIHdhaWxzLmxvZy5kZWJ1ZyhpbmNvbWluZ01lc3NhZ2UpCgkJdHJ5IHsKCQkJbWVzc2FnZSA9IEpTT04ucGFyc2UoaW5jb21pbmdNZXNzYWdlKQoJCX0gY2F0Y2ggKGUpIHsKCQkJd2FpbHMubG9nLmRlYnVnKCJJbnZhbGlkIEpTT04gcGFzc2VkIHRvIGNhbGxiYWNrOiAiICsgZS5tZXNzYWdlKQoJCQl3YWlscy5sb2cuZGVidWcoIk1lc3NhZ2U6ICIgKyBpbmNvbWluZ01lc3NhZ2UpCgkJCXJldHVybgoJCX0KCQljYWxsYmFja0lEID0gbWVzc2FnZS5jYWxsYmFja2lkCgkJY2FsbGJhY2tEYXRhID0gY2FsbGJhY2tzW2NhbGxiYWNrSURdCgkJaWYgKCFjYWxsYmFja0RhdGEpIHsKCQkJY29uc29sZS5lcnJvcigiQ2FsbGJhY2sgJyIgKyBjYWxsYmFja0lEICsgIicgbm90IHJlZ2lzdGVkISEhIikKCQkJcmV0dXJuCgkJfQoJCWNsZWFyVGltZW91dChjYWxsYmFja0RhdGEudGltZW91dEhhbmRsZSkKCQlkZWxldGUgY2FsbGJhY2tzW2NhbGxiYWNrSURdCgkJaWYgKG1lc3NhZ2UuZXJyb3IpIHsKCQkJcmV0dXJuIGNhbGxiYWNrRGF0YS5yZWplY3QobWVzc2FnZS5lcnJvcikKCQl9CgkJcmV0dXJuIGNhbGxiYWNrRGF0YS5yZXNvbHZlKG1lc3NhZ2UuZGF0YSkKCX0KCgkvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKCgkvKioqKioqKioqKioqKioqKioqKioqKioqKiogRXZlbnRzICoqKioqKioqKioqKioqKioqKioqKioqKioqLwoKCXZhciBldmVudExpc3RlbmVycyA9IHt9OwoKCS8vIFJlZ2lzdGVycyBldmVudCBsaXN0ZW5lcnMKCWZ1bmN0aW9uIG9uKGV2ZW50TmFtZSwgY2FsbGJhY2spIHsKCQlldmVudExpc3RlbmVyc1tldmVudE5hbWVdID0gZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSB8fCBbXTsKCQlldmVudExpc3RlbmVyc1tldmVudE5hbWVdLnB1c2goY2FsbGJhY2spOwoJfQoKCS8vIG5vdGlmeSBpbmZvcm1zIGZyb250ZW5kIGxpc3RlbmVycyB0aGF0IGFuIGV2ZW50IHdhcyBlbWl0dGVkIHdpdGggdGhlIGdpdmVuIGRhdGEKCWZ1bmN0aW9uIG5vdGlmeShldmVudE5hbWUsIGRhdGEpIHsKCQlpZiAoZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSkgewoJCQlldmVudExpc3RlbmVyc1tldmVudE5hbWVdLmZvckVhY2goZWxlbWVudCA9PiB7CgkJCQl2YXIgcGFyc2VkRGF0YSA9IFtdCgkJCQkvLyBQYXJzZSBkYXRhIGlmIHdlIGhhdmUgaXQKCQkJCWlmIChkYXRhKSB7CgkJCQkJdHJ5IHsKCQkJCQkJcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoZGF0YSk7CgkJCQkJfSBjYXRjaCAoZSkgewoJCQkJCQl3YWlscy5sb2cuZXJyb3IoIkludmFsaWQgSlNPTiBkYXRhIHNlbnQgdG8gbm90aWZ5LiBFdmVudCBuYW1lID0gIiArIGV2ZW50TmFtZSkKCQkJCQl9CgkJCQl9CgkJCQllbGVtZW50LmFwcGx5KG51bGwsIHBhcnNlZERhdGEpOwoJCQl9KTsKCQl9Cgl9CgoJLy8gZW1pdCBhbiBldmVudCB3aXRoIHRoZSBnaXZlbiBuYW1lIGFuZCBkYXRhCglmdW5jdGlvbiBlbWl0KGV2ZW50TmFtZSkgewoKCQkvLyBDYWxjdWxhdGUgdGhlIGRhdGEKCQl2YXIgZGF0YSA9IEpTT04uc3RyaW5naWZ5KFtdLnNsaWNlLmFwcGx5KGFyZ3VtZW50cykuc2xpY2UoMSkpOwoKCQkvLyBOb3RpZnkgYmFja2VuZAoJCW1lc3NhZ2UgPSB7CgkJCXR5cGU6ICJldmVudCIsCgkJCXBheWxvYWQ6IHsKCQkJCW5hbWU6IGV2ZW50TmFtZSwKCQkJCWRhdGE6IGRhdGEsCgkJCX0KCQl9CgkJZXh0ZXJuYWwuaW52b2tlKEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpKTsKCX0KCgkvLyBFdmVudHMgY2FsbHMKCXdpbmRvdy53YWlscy5ldmVudHMgPSB7IGVtaXQ6IGVtaXQsIG9uOiBvbiB9OwoKCS8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovCgoJLyoqKioqKioqKioqKioqKioqKioqKioqKiogTG9nZ2luZyAqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCgkvLyBTZW5kcyBhIGxvZyBtZXNzYWdlIHRvIHRoZSBiYWNrZW5kIHdpdGggdGhlIGdpdmVuCgkvLyBsZXZlbCArIG1lc3NhZ2UKCWZ1bmN0aW9uIHNlbmRMb2dNZXNzYWdlKGxldmVsLCBtZXNzYWdlKSB7CgoJCS8vIExvZyBNZXNzYWdlCgkJbWVzc2FnZSA9IHsKCQkJdHlwZTogImxvZyIsCgkJCXBheWxvYWQ6IHsKCQkJCWxldmVsOiBsZXZlbCwKCQkJCW1lc3NhZ2U6IG1lc3NhZ2UsCgkJCX0KCQl9CgkJZXh0ZXJuYWwuaW52b2tlKEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpKTsKCX0KCglmdW5jdGlvbiBsb2dEZWJ1ZyhtZXNzYWdlKSB7CgkJc2VuZExvZ01lc3NhZ2UoImRlYnVnIiwgbWVzc2FnZSk7Cgl9CglmdW5jdGlvbiBsb2dJbmZvKG1lc3NhZ2UpIHsKCQlzZW5kTG9nTWVzc2FnZSgiaW5mbyIsIG1lc3NhZ2UpOwoJfQoJZnVuY3Rpb24gbG9nV2FybmluZyhtZXNzYWdlKSB7CgkJc2VuZExvZ01lc3NhZ2UoIndhcm5pbmciLCBtZXNzYWdlKTsKCX0KCWZ1bmN0aW9uIGxvZ0Vycm9yKG1lc3NhZ2UpIHsKCQlzZW5kTG9nTWVzc2FnZSgiZXJyb3IiLCBtZXNzYWdlKTsKCX0KCWZ1bmN0aW9uIGxvZ0ZhdGFsKG1lc3NhZ2UpIHsKCQlzZW5kTG9nTWVzc2FnZSgiZmF0YWwiLCBtZXNzYWdlKTsKCX0KCgl3aW5kb3cud2FpbHMubG9nID0gewoJCWRlYnVnOiBsb2dEZWJ1ZywKCQlpbmZvOiBsb2dJbmZvLAoJCXdhcm5pbmc6IGxvZ1dhcm5pbmcsCgkJZXJyb3I6IGxvZ0Vycm9yLAoJCWZhdGFsOiBsb2dGYXRhbCwKCX07CgoJLyoqKioqKioqKioqKioqKioqKioqKioqKioqIEV4cG9ydHMgKioqKioqKioqKioqKioqKioqKioqKioqKi8KCgl3aW5kb3cud2FpbHMuXyA9IHsKCQluZXdCaW5kaW5nOiBuZXdCaW5kaW5nLAoJCWNhbGxiYWNrOiBjYWxsYmFjaywKCQlub3RpZnk6IG5vdGlmeSwKCQlzZW5kTG9nTWVzc2FnZTogc2VuZExvZ01lc3NhZ2UsCgkJY2FsbGJhY2tzOiBjYWxsYmFja3MsCgkJaW5qZWN0Q1NTOiBpbmplY3RDU1MsCgkJYWRkU2NyaXB0OiBhZGRTY3JpcHQsCgkJc2V0RG9jdW1lbnQ6IHNldERvY3VtZW50LAoJfQoKCS8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovCgoJLy8gTm90aWZ5IGJhY2tlbmQgdGhhdCB0aGUgcnVudGltZSBoYXMgZmluaXNoZWQgbG9hZGluZwoJd2luZG93LndhaWxzLmV2ZW50cy5lbWl0KCJ3YWlsczpsb2FkZWQiKTsKCn0pKCk=\"") + packr.PackJSONBytes("./assets/default", "default.html", "\"PGRpdiBpZD0iYXBwIj48L2Rpdj4=\"") + packr.PackJSONBytes("./assets/default", "jquery.3.3.1.min.js", "\"LyohIGpRdWVyeSB2My4zLjEgLWFqYXgsLWFqYXgvanNvbnAsLWFqYXgvbG9hZCwtYWpheC9wYXJzZVhNTCwtYWpheC9zY3JpcHQsLWFqYXgvdmFyL2xvY2F0aW9uLC1hamF4L3Zhci9ub25jZSwtYWpheC92YXIvcnF1ZXJ5LC1hamF4L3hociwtbWFuaXB1bGF0aW9uL19ldmFsVXJsLC1ldmVudC9hamF4LC1lZmZlY3RzLC1lZmZlY3RzL1R3ZWVuLC1lZmZlY3RzL2FuaW1hdGVkU2VsZWN0b3IgfCAoYykgSlMgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzIHwganF1ZXJ5Lm9yZy9saWNlbnNlICovCiFmdW5jdGlvbiAoZSwgdCkgeyAidXNlIHN0cmljdCI7ICJvYmplY3QiID09IHR5cGVvZiBtb2R1bGUgJiYgIm9iamVjdCIgPT0gdHlwZW9mIG1vZHVsZS5leHBvcnRzID8gbW9kdWxlLmV4cG9ydHMgPSBlLmRvY3VtZW50ID8gdChlLCAhMCkgOiBmdW5jdGlvbiAoZSkgeyBpZiAoIWUuZG9jdW1lbnQpIHRocm93IG5ldyBFcnJvcigialF1ZXJ5IHJlcXVpcmVzIGEgd2luZG93IHdpdGggYSBkb2N1bWVudCIpOyByZXR1cm4gdChlKSB9IDogdChlKSB9KCJ1bmRlZmluZWQiICE9IHR5cGVvZiB3aW5kb3cgPyB3aW5kb3cgOiB0aGlzLCBmdW5jdGlvbiAoZSwgdCkgeyAidXNlIHN0cmljdCI7IHZhciBuID0gW10sIHIgPSBlLmRvY3VtZW50LCBpID0gT2JqZWN0LmdldFByb3RvdHlwZU9mLCBvID0gbi5zbGljZSwgYSA9IG4uY29uY2F0LCB1ID0gbi5wdXNoLCBzID0gbi5pbmRleE9mLCBsID0ge30sIGMgPSBsLnRvU3RyaW5nLCBmID0gbC5oYXNPd25Qcm9wZXJ0eSwgZCA9IGYudG9TdHJpbmcsIHAgPSBkLmNhbGwoT2JqZWN0KSwgaCA9IHt9LCBnID0gZnVuY3Rpb24gZSh0KSB7IHJldHVybiAiZnVuY3Rpb24iID09IHR5cGVvZiB0ICYmICJudW1iZXIiICE9IHR5cGVvZiB0Lm5vZGVUeXBlIH0sIHYgPSBmdW5jdGlvbiBlKHQpIHsgcmV0dXJuIG51bGwgIT0gdCAmJiB0ID09PSB0LndpbmRvdyB9LCB5ID0geyB0eXBlOiAhMCwgc3JjOiAhMCwgbm9Nb2R1bGU6ICEwIH07IGZ1bmN0aW9uIG0oZSwgdCwgbikgeyB2YXIgaSwgbyA9ICh0ID0gdCB8fCByKS5jcmVhdGVFbGVtZW50KCJzY3JpcHQiKTsgaWYgKG8udGV4dCA9IGUsIG4pIGZvciAoaSBpbiB5KSBuW2ldICYmIChvW2ldID0gbltpXSk7IHQuaGVhZC5hcHBlbmRDaGlsZChvKS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKG8pIH0gZnVuY3Rpb24gYihlKSB7IHJldHVybiBudWxsID09IGUgPyBlICsgIiIgOiAib2JqZWN0IiA9PSB0eXBlb2YgZSB8fCAiZnVuY3Rpb24iID09IHR5cGVvZiBlID8gbFtjLmNhbGwoZSldIHx8ICJvYmplY3QiIDogdHlwZW9mIGUgfSB2YXIgeCA9ICIzLjMuMSAtYWpheCwtYWpheC9qc29ucCwtYWpheC9sb2FkLC1hamF4L3BhcnNlWE1MLC1hamF4L3NjcmlwdCwtYWpheC92YXIvbG9jYXRpb24sLWFqYXgvdmFyL25vbmNlLC1hamF4L3Zhci9ycXVlcnksLWFqYXgveGhyLC1tYW5pcHVsYXRpb24vX2V2YWxVcmwsLWV2ZW50L2FqYXgsLWVmZmVjdHMsLWVmZmVjdHMvVHdlZW4sLWVmZmVjdHMvYW5pbWF0ZWRTZWxlY3RvciIsIHcgPSBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gbmV3IHcuZm4uaW5pdChlLCB0KSB9LCBDID0gL15bXHNcdUZFRkZceEEwXSt8W1xzXHVGRUZGXHhBMF0rJC9nOyB3LmZuID0gdy5wcm90b3R5cGUgPSB7IGpxdWVyeTogeCwgY29uc3RydWN0b3I6IHcsIGxlbmd0aDogMCwgdG9BcnJheTogZnVuY3Rpb24gKCkgeyByZXR1cm4gby5jYWxsKHRoaXMpIH0sIGdldDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIG51bGwgPT0gZSA/IG8uY2FsbCh0aGlzKSA6IGUgPCAwID8gdGhpc1tlICsgdGhpcy5sZW5ndGhdIDogdGhpc1tlXSB9LCBwdXNoU3RhY2s6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gdy5tZXJnZSh0aGlzLmNvbnN0cnVjdG9yKCksIGUpOyByZXR1cm4gdC5wcmV2T2JqZWN0ID0gdGhpcywgdCB9LCBlYWNoOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdy5lYWNoKHRoaXMsIGUpIH0sIG1hcDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHRoaXMucHVzaFN0YWNrKHcubWFwKHRoaXMsIGZ1bmN0aW9uICh0LCBuKSB7IHJldHVybiBlLmNhbGwodCwgbiwgdCkgfSkpIH0sIHNsaWNlOiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLnB1c2hTdGFjayhvLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykpIH0sIGZpcnN0OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLmVxKDApIH0sIGxhc3Q6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMuZXEoLTEpIH0sIGVxOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IHRoaXMubGVuZ3RoLCBuID0gK2UgKyAoZSA8IDAgPyB0IDogMCk7IHJldHVybiB0aGlzLnB1c2hTdGFjayhuID49IDAgJiYgbiA8IHQgPyBbdGhpc1tuXV0gOiBbXSkgfSwgZW5kOiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLnByZXZPYmplY3QgfHwgdGhpcy5jb25zdHJ1Y3RvcigpIH0sIHB1c2g6IHUsIHNvcnQ6IG4uc29ydCwgc3BsaWNlOiBuLnNwbGljZSB9LCB3LmV4dGVuZCA9IHcuZm4uZXh0ZW5kID0gZnVuY3Rpb24gKCkgeyB2YXIgZSwgdCwgbiwgciwgaSwgbywgYSA9IGFyZ3VtZW50c1swXSB8fCB7fSwgdSA9IDEsIHMgPSBhcmd1bWVudHMubGVuZ3RoLCBsID0gITE7IGZvciAoImJvb2xlYW4iID09IHR5cGVvZiBhICYmIChsID0gYSwgYSA9IGFyZ3VtZW50c1t1XSB8fCB7fSwgdSsrKSwgIm9iamVjdCIgPT0gdHlwZW9mIGEgfHwgZyhhKSB8fCAoYSA9IHt9KSwgdSA9PT0gcyAmJiAoYSA9IHRoaXMsIHUtLSk7IHUgPCBzOyB1KyspaWYgKG51bGwgIT0gKGUgPSBhcmd1bWVudHNbdV0pKSBmb3IgKHQgaW4gZSkgbiA9IGFbdF0sIGEgIT09IChyID0gZVt0XSkgJiYgKGwgJiYgciAmJiAody5pc1BsYWluT2JqZWN0KHIpIHx8IChpID0gQXJyYXkuaXNBcnJheShyKSkpID8gKGkgPyAoaSA9ICExLCBvID0gbiAmJiBBcnJheS5pc0FycmF5KG4pID8gbiA6IFtdKSA6IG8gPSBuICYmIHcuaXNQbGFpbk9iamVjdChuKSA/IG4gOiB7fSwgYVt0XSA9IHcuZXh0ZW5kKGwsIG8sIHIpKSA6IHZvaWQgMCAhPT0gciAmJiAoYVt0XSA9IHIpKTsgcmV0dXJuIGEgfSwgdy5leHRlbmQoeyBleHBhbmRvOiAialF1ZXJ5IiArICh4ICsgTWF0aC5yYW5kb20oKSkucmVwbGFjZSgvXEQvZywgIiIpLCBpc1JlYWR5OiAhMCwgZXJyb3I6IGZ1bmN0aW9uIChlKSB7IHRocm93IG5ldyBFcnJvcihlKSB9LCBub29wOiBmdW5jdGlvbiAoKSB7IH0sIGlzUGxhaW5PYmplY3Q6IGZ1bmN0aW9uIChlKSB7IHZhciB0LCBuOyByZXR1cm4gISghZSB8fCAiW29iamVjdCBPYmplY3RdIiAhPT0gYy5jYWxsKGUpKSAmJiAoISh0ID0gaShlKSkgfHwgImZ1bmN0aW9uIiA9PSB0eXBlb2YgKG4gPSBmLmNhbGwodCwgImNvbnN0cnVjdG9yIikgJiYgdC5jb25zdHJ1Y3RvcikgJiYgZC5jYWxsKG4pID09PSBwKSB9LCBpc0VtcHR5T2JqZWN0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdDsgZm9yICh0IGluIGUpIHJldHVybiAhMTsgcmV0dXJuICEwIH0sIGdsb2JhbEV2YWw6IGZ1bmN0aW9uIChlKSB7IG0oZSkgfSwgZWFjaDogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIgPSAwOyBpZiAoVChlKSkgeyBmb3IgKG4gPSBlLmxlbmd0aDsgciA8IG47IHIrKylpZiAoITEgPT09IHQuY2FsbChlW3JdLCByLCBlW3JdKSkgYnJlYWsgfSBlbHNlIGZvciAociBpbiBlKSBpZiAoITEgPT09IHQuY2FsbChlW3JdLCByLCBlW3JdKSkgYnJlYWs7IHJldHVybiBlIH0sIHRyaW06IGZ1bmN0aW9uIChlKSB7IHJldHVybiBudWxsID09IGUgPyAiIiA6IChlICsgIiIpLnJlcGxhY2UoQywgIiIpIH0sIG1ha2VBcnJheTogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4gPSB0IHx8IFtdOyByZXR1cm4gbnVsbCAhPSBlICYmIChUKE9iamVjdChlKSkgPyB3Lm1lcmdlKG4sICJzdHJpbmciID09IHR5cGVvZiBlID8gW2VdIDogZSkgOiB1LmNhbGwobiwgZSkpLCBuIH0sIGluQXJyYXk6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBudWxsID09IHQgPyAtMSA6IHMuY2FsbCh0LCBlLCBuKSB9LCBtZXJnZTogZnVuY3Rpb24gKGUsIHQpIHsgZm9yICh2YXIgbiA9ICt0Lmxlbmd0aCwgciA9IDAsIGkgPSBlLmxlbmd0aDsgciA8IG47IHIrKyllW2krK10gPSB0W3JdOyByZXR1cm4gZS5sZW5ndGggPSBpLCBlIH0sIGdyZXA6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IGZvciAodmFyIHIsIGkgPSBbXSwgbyA9IDAsIGEgPSBlLmxlbmd0aCwgdSA9ICFuOyBvIDwgYTsgbysrKShyID0gIXQoZVtvXSwgbykpICE9PSB1ICYmIGkucHVzaChlW29dKTsgcmV0dXJuIGkgfSwgbWFwOiBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciwgaSwgbyA9IDAsIHUgPSBbXTsgaWYgKFQoZSkpIGZvciAociA9IGUubGVuZ3RoOyBvIDwgcjsgbysrKW51bGwgIT0gKGkgPSB0KGVbb10sIG8sIG4pKSAmJiB1LnB1c2goaSk7IGVsc2UgZm9yIChvIGluIGUpIG51bGwgIT0gKGkgPSB0KGVbb10sIG8sIG4pKSAmJiB1LnB1c2goaSk7IHJldHVybiBhLmFwcGx5KFtdLCB1KSB9LCBndWlkOiAxLCBzdXBwb3J0OiBoIH0pLCAiZnVuY3Rpb24iID09IHR5cGVvZiBTeW1ib2wgJiYgKHcuZm5bU3ltYm9sLml0ZXJhdG9yXSA9IG5bU3ltYm9sLml0ZXJhdG9yXSksIHcuZWFjaCgiQm9vbGVhbiBOdW1iZXIgU3RyaW5nIEZ1bmN0aW9uIEFycmF5IERhdGUgUmVnRXhwIE9iamVjdCBFcnJvciBTeW1ib2wiLnNwbGl0KCIgIiksIGZ1bmN0aW9uIChlLCB0KSB7IGxbIltvYmplY3QgIiArIHQgKyAiXSJdID0gdC50b0xvd2VyQ2FzZSgpIH0pOyBmdW5jdGlvbiBUKGUpIHsgdmFyIHQgPSAhIWUgJiYgImxlbmd0aCIgaW4gZSAmJiBlLmxlbmd0aCwgbiA9IGIoZSk7IHJldHVybiAhZyhlKSAmJiAhdihlKSAmJiAoImFycmF5IiA9PT0gbiB8fCAwID09PSB0IHx8ICJudW1iZXIiID09IHR5cGVvZiB0ICYmIHQgPiAwICYmIHQgLSAxIGluIGUpIH0gdmFyIEUgPSBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgbiwgciwgaSwgbywgYSwgdSwgcywgbCwgYywgZiwgZCwgcCwgaCwgZywgdiwgeSwgbSwgYiwgeCA9ICJzaXp6bGUiICsgMSAqIG5ldyBEYXRlLCB3ID0gZS5kb2N1bWVudCwgQyA9IDAsIFQgPSAwLCBFID0gYWUoKSwgTiA9IGFlKCksIGsgPSBhZSgpLCBBID0gZnVuY3Rpb24gKGUsIHQpIHsgcmV0dXJuIGUgPT09IHQgJiYgKGYgPSAhMCksIDAgfSwgRCA9IHt9Lmhhc093blByb3BlcnR5LCBTID0gW10sIEwgPSBTLnBvcCwgaiA9IFMucHVzaCwgcSA9IFMucHVzaCwgTyA9IFMuc2xpY2UsIFAgPSBmdW5jdGlvbiAoZSwgdCkgeyBmb3IgKHZhciBuID0gMCwgciA9IGUubGVuZ3RoOyBuIDwgcjsgbisrKWlmIChlW25dID09PSB0KSByZXR1cm4gbjsgcmV0dXJuIC0xIH0sIEggPSAiY2hlY2tlZHxzZWxlY3RlZHxhc3luY3xhdXRvZm9jdXN8YXV0b3BsYXl8Y29udHJvbHN8ZGVmZXJ8ZGlzYWJsZWR8aGlkZGVufGlzbWFwfGxvb3B8bXVsdGlwbGV8b3BlbnxyZWFkb25seXxyZXF1aXJlZHxzY29wZWQiLCBJID0gIltcXHgyMFxcdFxcclxcblxcZl0iLCBSID0gIig/OlxcXFwufFtcXHctXXxbXlwwLVxceGEwXSkrIiwgQiA9ICJcXFsiICsgSSArICIqKCIgKyBSICsgIikoPzoiICsgSSArICIqKFsqXiR8IX5dPz0pIiArIEkgKyAiKig/OicoKD86XFxcXC58W15cXFxcJ10pKiknfFwiKCg/OlxcXFwufFteXFxcXFwiXSkqKVwifCgiICsgUiArICIpKXwpIiArIEkgKyAiKlxcXSIsIE0gPSAiOigiICsgUiArICIpKD86XFwoKCgnKCg/OlxcXFwufFteXFxcXCddKSopJ3xcIigoPzpcXFxcLnxbXlxcXFxcIl0pKilcIil8KCg/OlxcXFwufFteXFxcXCgpW1xcXV18IiArIEIgKyAiKSopfC4qKVxcKXwpIiwgVyA9IG5ldyBSZWdFeHAoSSArICIrIiwgImciKSwgJCA9IG5ldyBSZWdFeHAoIl4iICsgSSArICIrfCgoPzpefFteXFxcXF0pKD86XFxcXC4pKikiICsgSSArICIrJCIsICJnIiksIEYgPSBuZXcgUmVnRXhwKCJeIiArIEkgKyAiKiwiICsgSSArICIqIiksIHogPSBuZXcgUmVnRXhwKCJeIiArIEkgKyAiKihbPit+XXwiICsgSSArICIpIiArIEkgKyAiKiIpLCBfID0gbmV3IFJlZ0V4cCgiPSIgKyBJICsgIiooW15cXF0nXCJdKj8pIiArIEkgKyAiKlxcXSIsICJnIiksIFUgPSBuZXcgUmVnRXhwKE0pLCBWID0gbmV3IFJlZ0V4cCgiXiIgKyBSICsgIiQiKSwgWCA9IHsgSUQ6IG5ldyBSZWdFeHAoIl4jKCIgKyBSICsgIikiKSwgQ0xBU1M6IG5ldyBSZWdFeHAoIl5cXC4oIiArIFIgKyAiKSIpLCBUQUc6IG5ldyBSZWdFeHAoIl4oIiArIFIgKyAifFsqXSkiKSwgQVRUUjogbmV3IFJlZ0V4cCgiXiIgKyBCKSwgUFNFVURPOiBuZXcgUmVnRXhwKCJeIiArIE0pLCBDSElMRDogbmV3IFJlZ0V4cCgiXjoob25seXxmaXJzdHxsYXN0fG50aHxudGgtbGFzdCktKGNoaWxkfG9mLXR5cGUpKD86XFwoIiArIEkgKyAiKihldmVufG9kZHwoKFsrLV18KShcXGQqKW58KSIgKyBJICsgIiooPzooWystXXwpIiArIEkgKyAiKihcXGQrKXwpKSIgKyBJICsgIipcXCl8KSIsICJpIiksIGJvb2w6IG5ldyBSZWdFeHAoIl4oPzoiICsgSCArICIpJCIsICJpIiksIG5lZWRzQ29udGV4dDogbmV3IFJlZ0V4cCgiXiIgKyBJICsgIipbPit+XXw6KGV2ZW58b2RkfGVxfGd0fGx0fG50aHxmaXJzdHxsYXN0KSg/OlxcKCIgKyBJICsgIiooKD86LVxcZCk/XFxkKikiICsgSSArICIqXFwpfCkoPz1bXi1dfCQpIiwgImkiKSB9LCBRID0gL14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWF8YnV0dG9uKSQvaSwgWSA9IC9eaFxkJC9pLCBHID0gL15bXntdK1x7XHMqXFtuYXRpdmUgXHcvLCBLID0gL14oPzojKFtcdy1dKyl8KFx3Kyl8XC4oW1x3LV0rKSkkLywgSiA9IC9bK35dLywgWiA9IG5ldyBSZWdFeHAoIlxcXFwoW1xcZGEtZl17MSw2fSIgKyBJICsgIj98KCIgKyBJICsgIil8LikiLCAiaWciKSwgZWUgPSBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciA9ICIweCIgKyB0IC0gNjU1MzY7IHJldHVybiByICE9PSByIHx8IG4gPyB0IDogciA8IDAgPyBTdHJpbmcuZnJvbUNoYXJDb2RlKHIgKyA2NTUzNikgOiBTdHJpbmcuZnJvbUNoYXJDb2RlKHIgPj4gMTAgfCA1NTI5NiwgMTAyMyAmIHIgfCA1NjMyMCkgfSwgdGUgPSAvKFtcMC1ceDFmXHg3Zl18Xi0/XGQpfF4tJHxbXlwwLVx4MWZceDdmLVx1RkZGRlx3LV0vZywgbmUgPSBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gdCA/ICJcMCIgPT09IGUgPyAiXHVmZmZkIiA6IGUuc2xpY2UoMCwgLTEpICsgIlxcIiArIGUuY2hhckNvZGVBdChlLmxlbmd0aCAtIDEpLnRvU3RyaW5nKDE2KSArICIgIiA6ICJcXCIgKyBlIH0sIHJlID0gZnVuY3Rpb24gKCkgeyBkKCkgfSwgaWUgPSBtZShmdW5jdGlvbiAoZSkgeyByZXR1cm4gITAgPT09IGUuZGlzYWJsZWQgJiYgKCJmb3JtIiBpbiBlIHx8ICJsYWJlbCIgaW4gZSkgfSwgeyBkaXI6ICJwYXJlbnROb2RlIiwgbmV4dDogImxlZ2VuZCIgfSk7IHRyeSB7IHEuYXBwbHkoUyA9IE8uY2FsbCh3LmNoaWxkTm9kZXMpLCB3LmNoaWxkTm9kZXMpLCBTW3cuY2hpbGROb2Rlcy5sZW5ndGhdLm5vZGVUeXBlIH0gY2F0Y2ggKGUpIHsgcSA9IHsgYXBwbHk6IFMubGVuZ3RoID8gZnVuY3Rpb24gKGUsIHQpIHsgai5hcHBseShlLCBPLmNhbGwodCkpIH0gOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IGUubGVuZ3RoLCByID0gMDsgd2hpbGUgKGVbbisrXSA9IHRbcisrXSk7IGUubGVuZ3RoID0gbiAtIDEgfSB9IH0gZnVuY3Rpb24gb2UoZSwgdCwgciwgaSkgeyB2YXIgbywgdSwgbCwgYywgZiwgaCwgeSwgbSA9IHQgJiYgdC5vd25lckRvY3VtZW50LCBDID0gdCA/IHQubm9kZVR5cGUgOiA5OyBpZiAociA9IHIgfHwgW10sICJzdHJpbmciICE9IHR5cGVvZiBlIHx8ICFlIHx8IDEgIT09IEMgJiYgOSAhPT0gQyAmJiAxMSAhPT0gQykgcmV0dXJuIHI7IGlmICghaSAmJiAoKHQgPyB0Lm93bmVyRG9jdW1lbnQgfHwgdCA6IHcpICE9PSBwICYmIGQodCksIHQgPSB0IHx8IHAsIGcpKSB7IGlmICgxMSAhPT0gQyAmJiAoZiA9IEsuZXhlYyhlKSkpIGlmIChvID0gZlsxXSkgeyBpZiAoOSA9PT0gQykgeyBpZiAoIShsID0gdC5nZXRFbGVtZW50QnlJZChvKSkpIHJldHVybiByOyBpZiAobC5pZCA9PT0gbykgcmV0dXJuIHIucHVzaChsKSwgciB9IGVsc2UgaWYgKG0gJiYgKGwgPSBtLmdldEVsZW1lbnRCeUlkKG8pKSAmJiBiKHQsIGwpICYmIGwuaWQgPT09IG8pIHJldHVybiByLnB1c2gobCksIHIgfSBlbHNlIHsgaWYgKGZbMl0pIHJldHVybiBxLmFwcGx5KHIsIHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoZSkpLCByOyBpZiAoKG8gPSBmWzNdKSAmJiBuLmdldEVsZW1lbnRzQnlDbGFzc05hbWUgJiYgdC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKSByZXR1cm4gcS5hcHBseShyLCB0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUobykpLCByIH0gaWYgKG4ucXNhICYmICFrW2UgKyAiICJdICYmICghdiB8fCAhdi50ZXN0KGUpKSkgeyBpZiAoMSAhPT0gQykgbSA9IHQsIHkgPSBlOyBlbHNlIGlmICgib2JqZWN0IiAhPT0gdC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpKSB7IChjID0gdC5nZXRBdHRyaWJ1dGUoImlkIikpID8gYyA9IGMucmVwbGFjZSh0ZSwgbmUpIDogdC5zZXRBdHRyaWJ1dGUoImlkIiwgYyA9IHgpLCB1ID0gKGggPSBhKGUpKS5sZW5ndGg7IHdoaWxlICh1LS0pIGhbdV0gPSAiIyIgKyBjICsgIiAiICsgeWUoaFt1XSk7IHkgPSBoLmpvaW4oIiwiKSwgbSA9IEoudGVzdChlKSAmJiBnZSh0LnBhcmVudE5vZGUpIHx8IHQgfSBpZiAoeSkgdHJ5IHsgcmV0dXJuIHEuYXBwbHkociwgbS5xdWVyeVNlbGVjdG9yQWxsKHkpKSwgciB9IGNhdGNoIChlKSB7IH0gZmluYWxseSB7IGMgPT09IHggJiYgdC5yZW1vdmVBdHRyaWJ1dGUoImlkIikgfSB9IH0gcmV0dXJuIHMoZS5yZXBsYWNlKCQsICIkMSIpLCB0LCByLCBpKSB9IGZ1bmN0aW9uIGFlKCkgeyB2YXIgZSA9IFtdOyBmdW5jdGlvbiB0KG4sIGkpIHsgcmV0dXJuIGUucHVzaChuICsgIiAiKSA+IHIuY2FjaGVMZW5ndGggJiYgZGVsZXRlIHRbZS5zaGlmdCgpXSwgdFtuICsgIiAiXSA9IGkgfSByZXR1cm4gdCB9IGZ1bmN0aW9uIHVlKGUpIHsgcmV0dXJuIGVbeF0gPSAhMCwgZSB9IGZ1bmN0aW9uIHNlKGUpIHsgdmFyIHQgPSBwLmNyZWF0ZUVsZW1lbnQoImZpZWxkc2V0Iik7IHRyeSB7IHJldHVybiAhIWUodCkgfSBjYXRjaCAoZSkgeyByZXR1cm4gITEgfSBmaW5hbGx5IHsgdC5wYXJlbnROb2RlICYmIHQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0KSwgdCA9IG51bGwgfSB9IGZ1bmN0aW9uIGxlKGUsIHQpIHsgdmFyIG4gPSBlLnNwbGl0KCJ8IiksIGkgPSBuLmxlbmd0aDsgd2hpbGUgKGktLSkgci5hdHRySGFuZGxlW25baV1dID0gdCB9IGZ1bmN0aW9uIGNlKGUsIHQpIHsgdmFyIG4gPSB0ICYmIGUsIHIgPSBuICYmIDEgPT09IGUubm9kZVR5cGUgJiYgMSA9PT0gdC5ub2RlVHlwZSAmJiBlLnNvdXJjZUluZGV4IC0gdC5zb3VyY2VJbmRleDsgaWYgKHIpIHJldHVybiByOyBpZiAobikgd2hpbGUgKG4gPSBuLm5leHRTaWJsaW5nKSBpZiAobiA9PT0gdCkgcmV0dXJuIC0xOyByZXR1cm4gZSA/IDEgOiAtMSB9IGZ1bmN0aW9uIGZlKGUpIHsgcmV0dXJuIGZ1bmN0aW9uICh0KSB7IHJldHVybiAiaW5wdXQiID09PSB0Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgJiYgdC50eXBlID09PSBlIH0gfSBmdW5jdGlvbiBkZShlKSB7IHJldHVybiBmdW5jdGlvbiAodCkgeyB2YXIgbiA9IHQubm9kZU5hbWUudG9Mb3dlckNhc2UoKTsgcmV0dXJuICgiaW5wdXQiID09PSBuIHx8ICJidXR0b24iID09PSBuKSAmJiB0LnR5cGUgPT09IGUgfSB9IGZ1bmN0aW9uIHBlKGUpIHsgcmV0dXJuIGZ1bmN0aW9uICh0KSB7IHJldHVybiAiZm9ybSIgaW4gdCA/IHQucGFyZW50Tm9kZSAmJiAhMSA9PT0gdC5kaXNhYmxlZCA/ICJsYWJlbCIgaW4gdCA/ICJsYWJlbCIgaW4gdC5wYXJlbnROb2RlID8gdC5wYXJlbnROb2RlLmRpc2FibGVkID09PSBlIDogdC5kaXNhYmxlZCA9PT0gZSA6IHQuaXNEaXNhYmxlZCA9PT0gZSB8fCB0LmlzRGlzYWJsZWQgIT09ICFlICYmIGllKHQpID09PSBlIDogdC5kaXNhYmxlZCA9PT0gZSA6ICJsYWJlbCIgaW4gdCAmJiB0LmRpc2FibGVkID09PSBlIH0gfSBmdW5jdGlvbiBoZShlKSB7IHJldHVybiB1ZShmdW5jdGlvbiAodCkgeyByZXR1cm4gdCA9ICt0LCB1ZShmdW5jdGlvbiAobiwgcikgeyB2YXIgaSwgbyA9IGUoW10sIG4ubGVuZ3RoLCB0KSwgYSA9IG8ubGVuZ3RoOyB3aGlsZSAoYS0tKSBuW2kgPSBvW2FdXSAmJiAobltpXSA9ICEocltpXSA9IG5baV0pKSB9KSB9KSB9IGZ1bmN0aW9uIGdlKGUpIHsgcmV0dXJuIGUgJiYgInVuZGVmaW5lZCIgIT0gdHlwZW9mIGUuZ2V0RWxlbWVudHNCeVRhZ05hbWUgJiYgZSB9IG4gPSBvZS5zdXBwb3J0ID0ge30sIG8gPSBvZS5pc1hNTCA9IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZSAmJiAoZS5vd25lckRvY3VtZW50IHx8IGUpLmRvY3VtZW50RWxlbWVudDsgcmV0dXJuICEhdCAmJiAiSFRNTCIgIT09IHQubm9kZU5hbWUgfSwgZCA9IG9lLnNldERvY3VtZW50ID0gZnVuY3Rpb24gKGUpIHsgdmFyIHQsIGksIGEgPSBlID8gZS5vd25lckRvY3VtZW50IHx8IGUgOiB3OyByZXR1cm4gYSAhPT0gcCAmJiA5ID09PSBhLm5vZGVUeXBlICYmIGEuZG9jdW1lbnRFbGVtZW50ID8gKHAgPSBhLCBoID0gcC5kb2N1bWVudEVsZW1lbnQsIGcgPSAhbyhwKSwgdyAhPT0gcCAmJiAoaSA9IHAuZGVmYXVsdFZpZXcpICYmIGkudG9wICE9PSBpICYmIChpLmFkZEV2ZW50TGlzdGVuZXIgPyBpLmFkZEV2ZW50TGlzdGVuZXIoInVubG9hZCIsIHJlLCAhMSkgOiBpLmF0dGFjaEV2ZW50ICYmIGkuYXR0YWNoRXZlbnQoIm9udW5sb2FkIiwgcmUpKSwgbi5hdHRyaWJ1dGVzID0gc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUuY2xhc3NOYW1lID0gImkiLCAhZS5nZXRBdHRyaWJ1dGUoImNsYXNzTmFtZSIpIH0pLCBuLmdldEVsZW1lbnRzQnlUYWdOYW1lID0gc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUuYXBwZW5kQ2hpbGQocC5jcmVhdGVDb21tZW50KCIiKSksICFlLmdldEVsZW1lbnRzQnlUYWdOYW1lKCIqIikubGVuZ3RoIH0pLCBuLmdldEVsZW1lbnRzQnlDbGFzc05hbWUgPSBHLnRlc3QocC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKSwgbi5nZXRCeUlkID0gc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGguYXBwZW5kQ2hpbGQoZSkuaWQgPSB4LCAhcC5nZXRFbGVtZW50c0J5TmFtZSB8fCAhcC5nZXRFbGVtZW50c0J5TmFtZSh4KS5sZW5ndGggfSksIG4uZ2V0QnlJZCA/IChyLmZpbHRlci5JRCA9IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZS5yZXBsYWNlKFosIGVlKTsgcmV0dXJuIGZ1bmN0aW9uIChlKSB7IHJldHVybiBlLmdldEF0dHJpYnV0ZSgiaWQiKSA9PT0gdCB9IH0sIHIuZmluZC5JRCA9IGZ1bmN0aW9uIChlLCB0KSB7IGlmICgidW5kZWZpbmVkIiAhPSB0eXBlb2YgdC5nZXRFbGVtZW50QnlJZCAmJiBnKSB7IHZhciBuID0gdC5nZXRFbGVtZW50QnlJZChlKTsgcmV0dXJuIG4gPyBbbl0gOiBbXSB9IH0pIDogKHIuZmlsdGVyLklEID0gZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSBlLnJlcGxhY2UoWiwgZWUpOyByZXR1cm4gZnVuY3Rpb24gKGUpIHsgdmFyIG4gPSAidW5kZWZpbmVkIiAhPSB0eXBlb2YgZS5nZXRBdHRyaWJ1dGVOb2RlICYmIGUuZ2V0QXR0cmlidXRlTm9kZSgiaWQiKTsgcmV0dXJuIG4gJiYgbi52YWx1ZSA9PT0gdCB9IH0sIHIuZmluZC5JRCA9IGZ1bmN0aW9uIChlLCB0KSB7IGlmICgidW5kZWZpbmVkIiAhPSB0eXBlb2YgdC5nZXRFbGVtZW50QnlJZCAmJiBnKSB7IHZhciBuLCByLCBpLCBvID0gdC5nZXRFbGVtZW50QnlJZChlKTsgaWYgKG8pIHsgaWYgKChuID0gby5nZXRBdHRyaWJ1dGVOb2RlKCJpZCIpKSAmJiBuLnZhbHVlID09PSBlKSByZXR1cm4gW29dOyBpID0gdC5nZXRFbGVtZW50c0J5TmFtZShlKSwgciA9IDA7IHdoaWxlIChvID0gaVtyKytdKSBpZiAoKG4gPSBvLmdldEF0dHJpYnV0ZU5vZGUoImlkIikpICYmIG4udmFsdWUgPT09IGUpIHJldHVybiBbb10gfSByZXR1cm4gW10gfSB9KSwgci5maW5kLlRBRyA9IG4uZ2V0RWxlbWVudHNCeVRhZ05hbWUgPyBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gInVuZGVmaW5lZCIgIT0gdHlwZW9mIHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUgPyB0LmdldEVsZW1lbnRzQnlUYWdOYW1lKGUpIDogbi5xc2EgPyB0LnF1ZXJ5U2VsZWN0b3JBbGwoZSkgOiB2b2lkIDAgfSA6IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCByID0gW10sIGkgPSAwLCBvID0gdC5nZXRFbGVtZW50c0J5VGFnTmFtZShlKTsgaWYgKCIqIiA9PT0gZSkgeyB3aGlsZSAobiA9IG9baSsrXSkgMSA9PT0gbi5ub2RlVHlwZSAmJiByLnB1c2gobik7IHJldHVybiByIH0gcmV0dXJuIG8gfSwgci5maW5kLkNMQVNTID0gbi5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lICYmIGZ1bmN0aW9uIChlLCB0KSB7IGlmICgidW5kZWZpbmVkIiAhPSB0eXBlb2YgdC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lICYmIGcpIHJldHVybiB0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoZSkgfSwgeSA9IFtdLCB2ID0gW10sIChuLnFzYSA9IEcudGVzdChwLnF1ZXJ5U2VsZWN0b3JBbGwpKSAmJiAoc2UoZnVuY3Rpb24gKGUpIHsgaC5hcHBlbmRDaGlsZChlKS5pbm5lckhUTUwgPSAiPGEgaWQ9JyIgKyB4ICsgIic+PC9hPjxzZWxlY3QgaWQ9JyIgKyB4ICsgIi1cclxcJyBtc2FsbG93Y2FwdHVyZT0nJz48b3B0aW9uIHNlbGVjdGVkPScnPjwvb3B0aW9uPjwvc2VsZWN0PiIsIGUucXVlcnlTZWxlY3RvckFsbCgiW21zYWxsb3djYXB0dXJlXj0nJ10iKS5sZW5ndGggJiYgdi5wdXNoKCJbKl4kXT0iICsgSSArICIqKD86Jyd8XCJcIikiKSwgZS5xdWVyeVNlbGVjdG9yQWxsKCJbc2VsZWN0ZWRdIikubGVuZ3RoIHx8IHYucHVzaCgiXFxbIiArIEkgKyAiKig/OnZhbHVlfCIgKyBIICsgIikiKSwgZS5xdWVyeVNlbGVjdG9yQWxsKCJbaWR+PSIgKyB4ICsgIi1dIikubGVuZ3RoIHx8IHYucHVzaCgifj0iKSwgZS5xdWVyeVNlbGVjdG9yQWxsKCI6Y2hlY2tlZCIpLmxlbmd0aCB8fCB2LnB1c2goIjpjaGVja2VkIiksIGUucXVlcnlTZWxlY3RvckFsbCgiYSMiICsgeCArICIrKiIpLmxlbmd0aCB8fCB2LnB1c2goIi4jLitbK35dIikgfSksIHNlKGZ1bmN0aW9uIChlKSB7IGUuaW5uZXJIVE1MID0gIjxhIGhyZWY9JycgZGlzYWJsZWQ9J2Rpc2FibGVkJz48L2E+PHNlbGVjdCBkaXNhYmxlZD0nZGlzYWJsZWQnPjxvcHRpb24vPjwvc2VsZWN0PiI7IHZhciB0ID0gcC5jcmVhdGVFbGVtZW50KCJpbnB1dCIpOyB0LnNldEF0dHJpYnV0ZSgidHlwZSIsICJoaWRkZW4iKSwgZS5hcHBlbmRDaGlsZCh0KS5zZXRBdHRyaWJ1dGUoIm5hbWUiLCAiRCIpLCBlLnF1ZXJ5U2VsZWN0b3JBbGwoIltuYW1lPWRdIikubGVuZ3RoICYmIHYucHVzaCgibmFtZSIgKyBJICsgIipbKl4kfCF+XT89IiksIDIgIT09IGUucXVlcnlTZWxlY3RvckFsbCgiOmVuYWJsZWQiKS5sZW5ndGggJiYgdi5wdXNoKCI6ZW5hYmxlZCIsICI6ZGlzYWJsZWQiKSwgaC5hcHBlbmRDaGlsZChlKS5kaXNhYmxlZCA9ICEwLCAyICE9PSBlLnF1ZXJ5U2VsZWN0b3JBbGwoIjpkaXNhYmxlZCIpLmxlbmd0aCAmJiB2LnB1c2goIjplbmFibGVkIiwgIjpkaXNhYmxlZCIpLCBlLnF1ZXJ5U2VsZWN0b3JBbGwoIiosOngiKSwgdi5wdXNoKCIsLio6IikgfSkpLCAobi5tYXRjaGVzU2VsZWN0b3IgPSBHLnRlc3QobSA9IGgubWF0Y2hlcyB8fCBoLndlYmtpdE1hdGNoZXNTZWxlY3RvciB8fCBoLm1vek1hdGNoZXNTZWxlY3RvciB8fCBoLm9NYXRjaGVzU2VsZWN0b3IgfHwgaC5tc01hdGNoZXNTZWxlY3RvcikpICYmIHNlKGZ1bmN0aW9uIChlKSB7IG4uZGlzY29ubmVjdGVkTWF0Y2ggPSBtLmNhbGwoZSwgIioiKSwgbS5jYWxsKGUsICJbcyE9JyddOngiKSwgeS5wdXNoKCIhPSIsIE0pIH0pLCB2ID0gdi5sZW5ndGggJiYgbmV3IFJlZ0V4cCh2LmpvaW4oInwiKSksIHkgPSB5Lmxlbmd0aCAmJiBuZXcgUmVnRXhwKHkuam9pbigifCIpKSwgdCA9IEcudGVzdChoLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKSwgYiA9IHQgfHwgRy50ZXN0KGguY29udGFpbnMpID8gZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4gPSA5ID09PSBlLm5vZGVUeXBlID8gZS5kb2N1bWVudEVsZW1lbnQgOiBlLCByID0gdCAmJiB0LnBhcmVudE5vZGU7IHJldHVybiBlID09PSByIHx8ICEoIXIgfHwgMSAhPT0gci5ub2RlVHlwZSB8fCAhKG4uY29udGFpbnMgPyBuLmNvbnRhaW5zKHIpIDogZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiAmJiAxNiAmIGUuY29tcGFyZURvY3VtZW50UG9zaXRpb24ocikpKSB9IDogZnVuY3Rpb24gKGUsIHQpIHsgaWYgKHQpIHdoaWxlICh0ID0gdC5wYXJlbnROb2RlKSBpZiAodCA9PT0gZSkgcmV0dXJuICEwOyByZXR1cm4gITEgfSwgQSA9IHQgPyBmdW5jdGlvbiAoZSwgdCkgeyBpZiAoZSA9PT0gdCkgcmV0dXJuIGYgPSAhMCwgMDsgdmFyIHIgPSAhZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiAtICF0LmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uOyByZXR1cm4gciB8fCAoMSAmIChyID0gKGUub3duZXJEb2N1bWVudCB8fCBlKSA9PT0gKHQub3duZXJEb2N1bWVudCB8fCB0KSA/IGUuY29tcGFyZURvY3VtZW50UG9zaXRpb24odCkgOiAxKSB8fCAhbi5zb3J0RGV0YWNoZWQgJiYgdC5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihlKSA9PT0gciA/IGUgPT09IHAgfHwgZS5vd25lckRvY3VtZW50ID09PSB3ICYmIGIodywgZSkgPyAtMSA6IHQgPT09IHAgfHwgdC5vd25lckRvY3VtZW50ID09PSB3ICYmIGIodywgdCkgPyAxIDogYyA/IFAoYywgZSkgLSBQKGMsIHQpIDogMCA6IDQgJiByID8gLTEgOiAxKSB9IDogZnVuY3Rpb24gKGUsIHQpIHsgaWYgKGUgPT09IHQpIHJldHVybiBmID0gITAsIDA7IHZhciBuLCByID0gMCwgaSA9IGUucGFyZW50Tm9kZSwgbyA9IHQucGFyZW50Tm9kZSwgYSA9IFtlXSwgdSA9IFt0XTsgaWYgKCFpIHx8ICFvKSByZXR1cm4gZSA9PT0gcCA/IC0xIDogdCA9PT0gcCA/IDEgOiBpID8gLTEgOiBvID8gMSA6IGMgPyBQKGMsIGUpIC0gUChjLCB0KSA6IDA7IGlmIChpID09PSBvKSByZXR1cm4gY2UoZSwgdCk7IG4gPSBlOyB3aGlsZSAobiA9IG4ucGFyZW50Tm9kZSkgYS51bnNoaWZ0KG4pOyBuID0gdDsgd2hpbGUgKG4gPSBuLnBhcmVudE5vZGUpIHUudW5zaGlmdChuKTsgd2hpbGUgKGFbcl0gPT09IHVbcl0pIHIrKzsgcmV0dXJuIHIgPyBjZShhW3JdLCB1W3JdKSA6IGFbcl0gPT09IHcgPyAtMSA6IHVbcl0gPT09IHcgPyAxIDogMCB9LCBwKSA6IHAgfSwgb2UubWF0Y2hlcyA9IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiBvZShlLCBudWxsLCBudWxsLCB0KSB9LCBvZS5tYXRjaGVzU2VsZWN0b3IgPSBmdW5jdGlvbiAoZSwgdCkgeyBpZiAoKGUub3duZXJEb2N1bWVudCB8fCBlKSAhPT0gcCAmJiBkKGUpLCB0ID0gdC5yZXBsYWNlKF8sICI9JyQxJ10iKSwgbi5tYXRjaGVzU2VsZWN0b3IgJiYgZyAmJiAha1t0ICsgIiAiXSAmJiAoIXkgfHwgIXkudGVzdCh0KSkgJiYgKCF2IHx8ICF2LnRlc3QodCkpKSB0cnkgeyB2YXIgciA9IG0uY2FsbChlLCB0KTsgaWYgKHIgfHwgbi5kaXNjb25uZWN0ZWRNYXRjaCB8fCBlLmRvY3VtZW50ICYmIDExICE9PSBlLmRvY3VtZW50Lm5vZGVUeXBlKSByZXR1cm4gciB9IGNhdGNoIChlKSB7IH0gcmV0dXJuIG9lKHQsIHAsIG51bGwsIFtlXSkubGVuZ3RoID4gMCB9LCBvZS5jb250YWlucyA9IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiAoZS5vd25lckRvY3VtZW50IHx8IGUpICE9PSBwICYmIGQoZSksIGIoZSwgdCkgfSwgb2UuYXR0ciA9IGZ1bmN0aW9uIChlLCB0KSB7IChlLm93bmVyRG9jdW1lbnQgfHwgZSkgIT09IHAgJiYgZChlKTsgdmFyIGkgPSByLmF0dHJIYW5kbGVbdC50b0xvd2VyQ2FzZSgpXSwgbyA9IGkgJiYgRC5jYWxsKHIuYXR0ckhhbmRsZSwgdC50b0xvd2VyQ2FzZSgpKSA/IGkoZSwgdCwgIWcpIDogdm9pZCAwOyByZXR1cm4gdm9pZCAwICE9PSBvID8gbyA6IG4uYXR0cmlidXRlcyB8fCAhZyA/IGUuZ2V0QXR0cmlidXRlKHQpIDogKG8gPSBlLmdldEF0dHJpYnV0ZU5vZGUodCkpICYmIG8uc3BlY2lmaWVkID8gby52YWx1ZSA6IG51bGwgfSwgb2UuZXNjYXBlID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuIChlICsgIiIpLnJlcGxhY2UodGUsIG5lKSB9LCBvZS5lcnJvciA9IGZ1bmN0aW9uIChlKSB7IHRocm93IG5ldyBFcnJvcigiU3ludGF4IGVycm9yLCB1bnJlY29nbml6ZWQgZXhwcmVzc2lvbjogIiArIGUpIH0sIG9lLnVuaXF1ZVNvcnQgPSBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgciA9IFtdLCBpID0gMCwgbyA9IDA7IGlmIChmID0gIW4uZGV0ZWN0RHVwbGljYXRlcywgYyA9ICFuLnNvcnRTdGFibGUgJiYgZS5zbGljZSgwKSwgZS5zb3J0KEEpLCBmKSB7IHdoaWxlICh0ID0gZVtvKytdKSB0ID09PSBlW29dICYmIChpID0gci5wdXNoKG8pKTsgd2hpbGUgKGktLSkgZS5zcGxpY2UocltpXSwgMSkgfSByZXR1cm4gYyA9IG51bGwsIGUgfSwgaSA9IG9lLmdldFRleHQgPSBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgbiA9ICIiLCByID0gMCwgbyA9IGUubm9kZVR5cGU7IGlmIChvKSB7IGlmICgxID09PSBvIHx8IDkgPT09IG8gfHwgMTEgPT09IG8pIHsgaWYgKCJzdHJpbmciID09IHR5cGVvZiBlLnRleHRDb250ZW50KSByZXR1cm4gZS50ZXh0Q29udGVudDsgZm9yIChlID0gZS5maXJzdENoaWxkOyBlOyBlID0gZS5uZXh0U2libGluZyluICs9IGkoZSkgfSBlbHNlIGlmICgzID09PSBvIHx8IDQgPT09IG8pIHJldHVybiBlLm5vZGVWYWx1ZSB9IGVsc2Ugd2hpbGUgKHQgPSBlW3IrK10pIG4gKz0gaSh0KTsgcmV0dXJuIG4gfSwgKHIgPSBvZS5zZWxlY3RvcnMgPSB7IGNhY2hlTGVuZ3RoOiA1MCwgY3JlYXRlUHNldWRvOiB1ZSwgbWF0Y2g6IFgsIGF0dHJIYW5kbGU6IHt9LCBmaW5kOiB7fSwgcmVsYXRpdmU6IHsgIj4iOiB7IGRpcjogInBhcmVudE5vZGUiLCBmaXJzdDogITAgfSwgIiAiOiB7IGRpcjogInBhcmVudE5vZGUiIH0sICIrIjogeyBkaXI6ICJwcmV2aW91c1NpYmxpbmciLCBmaXJzdDogITAgfSwgIn4iOiB7IGRpcjogInByZXZpb3VzU2libGluZyIgfSB9LCBwcmVGaWx0ZXI6IHsgQVRUUjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGVbMV0gPSBlWzFdLnJlcGxhY2UoWiwgZWUpLCBlWzNdID0gKGVbM10gfHwgZVs0XSB8fCBlWzVdIHx8ICIiKS5yZXBsYWNlKFosIGVlKSwgIn49IiA9PT0gZVsyXSAmJiAoZVszXSA9ICIgIiArIGVbM10gKyAiICIpLCBlLnNsaWNlKDAsIDQpIH0sIENISUxEOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZVsxXSA9IGVbMV0udG9Mb3dlckNhc2UoKSwgIm50aCIgPT09IGVbMV0uc2xpY2UoMCwgMykgPyAoZVszXSB8fCBvZS5lcnJvcihlWzBdKSwgZVs0XSA9ICsoZVs0XSA/IGVbNV0gKyAoZVs2XSB8fCAxKSA6IDIgKiAoImV2ZW4iID09PSBlWzNdIHx8ICJvZGQiID09PSBlWzNdKSksIGVbNV0gPSArKGVbN10gKyBlWzhdIHx8ICJvZGQiID09PSBlWzNdKSkgOiBlWzNdICYmIG9lLmVycm9yKGVbMF0pLCBlIH0sIFBTRVVETzogZnVuY3Rpb24gKGUpIHsgdmFyIHQsIG4gPSAhZVs2XSAmJiBlWzJdOyByZXR1cm4gWC5DSElMRC50ZXN0KGVbMF0pID8gbnVsbCA6IChlWzNdID8gZVsyXSA9IGVbNF0gfHwgZVs1XSB8fCAiIiA6IG4gJiYgVS50ZXN0KG4pICYmICh0ID0gYShuLCAhMCkpICYmICh0ID0gbi5pbmRleE9mKCIpIiwgbi5sZW5ndGggLSB0KSAtIG4ubGVuZ3RoKSAmJiAoZVswXSA9IGVbMF0uc2xpY2UoMCwgdCksIGVbMl0gPSBuLnNsaWNlKDAsIHQpKSwgZS5zbGljZSgwLCAzKSkgfSB9LCBmaWx0ZXI6IHsgVEFHOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGUucmVwbGFjZShaLCBlZSkudG9Mb3dlckNhc2UoKTsgcmV0dXJuICIqIiA9PT0gZSA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuICEwIH0gOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZS5ub2RlTmFtZSAmJiBlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IHQgfSB9LCBDTEFTUzogZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSBFW2UgKyAiICJdOyByZXR1cm4gdCB8fCAodCA9IG5ldyBSZWdFeHAoIihefCIgKyBJICsgIikiICsgZSArICIoIiArIEkgKyAifCQpIikpICYmIEUoZSwgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHQudGVzdCgic3RyaW5nIiA9PSB0eXBlb2YgZS5jbGFzc05hbWUgJiYgZS5jbGFzc05hbWUgfHwgInVuZGVmaW5lZCIgIT0gdHlwZW9mIGUuZ2V0QXR0cmlidXRlICYmIGUuZ2V0QXR0cmlidXRlKCJjbGFzcyIpIHx8ICIiKSB9KSB9LCBBVFRSOiBmdW5jdGlvbiAoZSwgdCwgbikgeyByZXR1cm4gZnVuY3Rpb24gKHIpIHsgdmFyIGkgPSBvZS5hdHRyKHIsIGUpOyByZXR1cm4gbnVsbCA9PSBpID8gIiE9IiA9PT0gdCA6ICF0IHx8IChpICs9ICIiLCAiPSIgPT09IHQgPyBpID09PSBuIDogIiE9IiA9PT0gdCA/IGkgIT09IG4gOiAiXj0iID09PSB0ID8gbiAmJiAwID09PSBpLmluZGV4T2YobikgOiAiKj0iID09PSB0ID8gbiAmJiBpLmluZGV4T2YobikgPiAtMSA6ICIkPSIgPT09IHQgPyBuICYmIGkuc2xpY2UoLW4ubGVuZ3RoKSA9PT0gbiA6ICJ+PSIgPT09IHQgPyAoIiAiICsgaS5yZXBsYWNlKFcsICIgIikgKyAiICIpLmluZGV4T2YobikgPiAtMSA6ICJ8PSIgPT09IHQgJiYgKGkgPT09IG4gfHwgaS5zbGljZSgwLCBuLmxlbmd0aCArIDEpID09PSBuICsgIi0iKSkgfSB9LCBDSElMRDogZnVuY3Rpb24gKGUsIHQsIG4sIHIsIGkpIHsgdmFyIG8gPSAibnRoIiAhPT0gZS5zbGljZSgwLCAzKSwgYSA9ICJsYXN0IiAhPT0gZS5zbGljZSgtNCksIHUgPSAib2YtdHlwZSIgPT09IHQ7IHJldHVybiAxID09PSByICYmIDAgPT09IGkgPyBmdW5jdGlvbiAoZSkgeyByZXR1cm4gISFlLnBhcmVudE5vZGUgfSA6IGZ1bmN0aW9uICh0LCBuLCBzKSB7IHZhciBsLCBjLCBmLCBkLCBwLCBoLCBnID0gbyAhPT0gYSA/ICJuZXh0U2libGluZyIgOiAicHJldmlvdXNTaWJsaW5nIiwgdiA9IHQucGFyZW50Tm9kZSwgeSA9IHUgJiYgdC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpLCBtID0gIXMgJiYgIXUsIGIgPSAhMTsgaWYgKHYpIHsgaWYgKG8pIHsgd2hpbGUgKGcpIHsgZCA9IHQ7IHdoaWxlIChkID0gZFtnXSkgaWYgKHUgPyBkLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IHkgOiAxID09PSBkLm5vZGVUeXBlKSByZXR1cm4gITE7IGggPSBnID0gIm9ubHkiID09PSBlICYmICFoICYmICJuZXh0U2libGluZyIgfSByZXR1cm4gITAgfSBpZiAoaCA9IFthID8gdi5maXJzdENoaWxkIDogdi5sYXN0Q2hpbGRdLCBhICYmIG0pIHsgYiA9IChwID0gKGwgPSAoYyA9IChmID0gKGQgPSB2KVt4XSB8fCAoZFt4XSA9IHt9KSlbZC51bmlxdWVJRF0gfHwgKGZbZC51bmlxdWVJRF0gPSB7fSkpW2VdIHx8IFtdKVswXSA9PT0gQyAmJiBsWzFdKSAmJiBsWzJdLCBkID0gcCAmJiB2LmNoaWxkTm9kZXNbcF07IHdoaWxlIChkID0gKytwICYmIGQgJiYgZFtnXSB8fCAoYiA9IHAgPSAwKSB8fCBoLnBvcCgpKSBpZiAoMSA9PT0gZC5ub2RlVHlwZSAmJiArK2IgJiYgZCA9PT0gdCkgeyBjW2VdID0gW0MsIHAsIGJdOyBicmVhayB9IH0gZWxzZSBpZiAobSAmJiAoYiA9IHAgPSAobCA9IChjID0gKGYgPSAoZCA9IHQpW3hdIHx8IChkW3hdID0ge30pKVtkLnVuaXF1ZUlEXSB8fCAoZltkLnVuaXF1ZUlEXSA9IHt9KSlbZV0gfHwgW10pWzBdID09PSBDICYmIGxbMV0pLCAhMSA9PT0gYikgd2hpbGUgKGQgPSArK3AgJiYgZCAmJiBkW2ddIHx8IChiID0gcCA9IDApIHx8IGgucG9wKCkpIGlmICgodSA/IGQubm9kZU5hbWUudG9Mb3dlckNhc2UoKSA9PT0geSA6IDEgPT09IGQubm9kZVR5cGUpICYmICsrYiAmJiAobSAmJiAoKGMgPSAoZiA9IGRbeF0gfHwgKGRbeF0gPSB7fSkpW2QudW5pcXVlSURdIHx8IChmW2QudW5pcXVlSURdID0ge30pKVtlXSA9IFtDLCBiXSksIGQgPT09IHQpKSBicmVhazsgcmV0dXJuIChiIC09IGkpID09PSByIHx8IGIgJSByID09IDAgJiYgYiAvIHIgPj0gMCB9IH0gfSwgUFNFVURPOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiwgaSA9IHIucHNldWRvc1tlXSB8fCByLnNldEZpbHRlcnNbZS50b0xvd2VyQ2FzZSgpXSB8fCBvZS5lcnJvcigidW5zdXBwb3J0ZWQgcHNldWRvOiAiICsgZSk7IHJldHVybiBpW3hdID8gaSh0KSA6IGkubGVuZ3RoID4gMSA/IChuID0gW2UsIGUsICIiLCB0XSwgci5zZXRGaWx0ZXJzLmhhc093blByb3BlcnR5KGUudG9Mb3dlckNhc2UoKSkgPyB1ZShmdW5jdGlvbiAoZSwgbikgeyB2YXIgciwgbyA9IGkoZSwgdCksIGEgPSBvLmxlbmd0aDsgd2hpbGUgKGEtLSkgZVtyID0gUChlLCBvW2FdKV0gPSAhKG5bcl0gPSBvW2FdKSB9KSA6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBpKGUsIDAsIG4pIH0pIDogaSB9IH0sIHBzZXVkb3M6IHsgbm90OiB1ZShmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IFtdLCBuID0gW10sIHIgPSB1KGUucmVwbGFjZSgkLCAiJDEiKSk7IHJldHVybiByW3hdID8gdWUoZnVuY3Rpb24gKGUsIHQsIG4sIGkpIHsgdmFyIG8sIGEgPSByKGUsIG51bGwsIGksIFtdKSwgdSA9IGUubGVuZ3RoOyB3aGlsZSAodS0tKSAobyA9IGFbdV0pICYmIChlW3VdID0gISh0W3VdID0gbykpIH0pIDogZnVuY3Rpb24gKGUsIGksIG8pIHsgcmV0dXJuIHRbMF0gPSBlLCByKHQsIG51bGwsIG8sIG4pLCB0WzBdID0gbnVsbCwgIW4ucG9wKCkgfSB9KSwgaGFzOiB1ZShmdW5jdGlvbiAoZSkgeyByZXR1cm4gZnVuY3Rpb24gKHQpIHsgcmV0dXJuIG9lKGUsIHQpLmxlbmd0aCA+IDAgfSB9KSwgY29udGFpbnM6IHVlKGZ1bmN0aW9uIChlKSB7IHJldHVybiBlID0gZS5yZXBsYWNlKFosIGVlKSwgZnVuY3Rpb24gKHQpIHsgcmV0dXJuICh0LnRleHRDb250ZW50IHx8IHQuaW5uZXJUZXh0IHx8IGkodCkpLmluZGV4T2YoZSkgPiAtMSB9IH0pLCBsYW5nOiB1ZShmdW5jdGlvbiAoZSkgeyByZXR1cm4gVi50ZXN0KGUgfHwgIiIpIHx8IG9lLmVycm9yKCJ1bnN1cHBvcnRlZCBsYW5nOiAiICsgZSksIGUgPSBlLnJlcGxhY2UoWiwgZWUpLnRvTG93ZXJDYXNlKCksIGZ1bmN0aW9uICh0KSB7IHZhciBuOyBkbyB7IGlmIChuID0gZyA/IHQubGFuZyA6IHQuZ2V0QXR0cmlidXRlKCJ4bWw6bGFuZyIpIHx8IHQuZ2V0QXR0cmlidXRlKCJsYW5nIikpIHJldHVybiAobiA9IG4udG9Mb3dlckNhc2UoKSkgPT09IGUgfHwgMCA9PT0gbi5pbmRleE9mKGUgKyAiLSIpIH0gd2hpbGUgKCh0ID0gdC5wYXJlbnROb2RlKSAmJiAxID09PSB0Lm5vZGVUeXBlKTsgcmV0dXJuICExIH0gfSksIHRhcmdldDogZnVuY3Rpb24gKHQpIHsgdmFyIG4gPSBlLmxvY2F0aW9uICYmIGUubG9jYXRpb24uaGFzaDsgcmV0dXJuIG4gJiYgbi5zbGljZSgxKSA9PT0gdC5pZCB9LCByb290OiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZSA9PT0gaCB9LCBmb2N1czogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUgPT09IHAuYWN0aXZlRWxlbWVudCAmJiAoIXAuaGFzRm9jdXMgfHwgcC5oYXNGb2N1cygpKSAmJiAhIShlLnR5cGUgfHwgZS5ocmVmIHx8IH5lLnRhYkluZGV4KSB9LCBlbmFibGVkOiBwZSghMSksIGRpc2FibGVkOiBwZSghMCksIGNoZWNrZWQ6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpOyByZXR1cm4gImlucHV0IiA9PT0gdCAmJiAhIWUuY2hlY2tlZCB8fCAib3B0aW9uIiA9PT0gdCAmJiAhIWUuc2VsZWN0ZWQgfSwgc2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBlLnBhcmVudE5vZGUgJiYgZS5wYXJlbnROb2RlLnNlbGVjdGVkSW5kZXgsICEwID09PSBlLnNlbGVjdGVkIH0sIGVtcHR5OiBmdW5jdGlvbiAoZSkgeyBmb3IgKGUgPSBlLmZpcnN0Q2hpbGQ7IGU7IGUgPSBlLm5leHRTaWJsaW5nKWlmIChlLm5vZGVUeXBlIDwgNikgcmV0dXJuICExOyByZXR1cm4gITAgfSwgcGFyZW50OiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gIXIucHNldWRvcy5lbXB0eShlKSB9LCBoZWFkZXI6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBZLnRlc3QoZS5ub2RlTmFtZSkgfSwgaW5wdXQ6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBRLnRlc3QoZS5ub2RlTmFtZSkgfSwgYnV0dG9uOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGUubm9kZU5hbWUudG9Mb3dlckNhc2UoKTsgcmV0dXJuICJpbnB1dCIgPT09IHQgJiYgImJ1dHRvbiIgPT09IGUudHlwZSB8fCAiYnV0dG9uIiA9PT0gdCB9LCB0ZXh0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdDsgcmV0dXJuICJpbnB1dCIgPT09IGUubm9kZU5hbWUudG9Mb3dlckNhc2UoKSAmJiAidGV4dCIgPT09IGUudHlwZSAmJiAobnVsbCA9PSAodCA9IGUuZ2V0QXR0cmlidXRlKCJ0eXBlIikpIHx8ICJ0ZXh0IiA9PT0gdC50b0xvd2VyQ2FzZSgpKSB9LCBmaXJzdDogaGUoZnVuY3Rpb24gKCkgeyByZXR1cm4gWzBdIH0pLCBsYXN0OiBoZShmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gW3QgLSAxXSB9KSwgZXE6IGhlKGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBbbiA8IDAgPyBuICsgdCA6IG5dIH0pLCBldmVuOiBoZShmdW5jdGlvbiAoZSwgdCkgeyBmb3IgKHZhciBuID0gMDsgbiA8IHQ7IG4gKz0gMillLnB1c2gobik7IHJldHVybiBlIH0pLCBvZGQ6IGhlKGZ1bmN0aW9uIChlLCB0KSB7IGZvciAodmFyIG4gPSAxOyBuIDwgdDsgbiArPSAyKWUucHVzaChuKTsgcmV0dXJuIGUgfSksIGx0OiBoZShmdW5jdGlvbiAoZSwgdCwgbikgeyBmb3IgKHZhciByID0gbiA8IDAgPyBuICsgdCA6IG47IC0tciA+PSAwOyllLnB1c2gocik7IHJldHVybiBlIH0pLCBndDogaGUoZnVuY3Rpb24gKGUsIHQsIG4pIHsgZm9yICh2YXIgciA9IG4gPCAwID8gbiArIHQgOiBuOyArK3IgPCB0OyllLnB1c2gocik7IHJldHVybiBlIH0pIH0gfSkucHNldWRvcy5udGggPSByLnBzZXVkb3MuZXE7IGZvciAodCBpbiB7IHJhZGlvOiAhMCwgY2hlY2tib3g6ICEwLCBmaWxlOiAhMCwgcGFzc3dvcmQ6ICEwLCBpbWFnZTogITAgfSkgci5wc2V1ZG9zW3RdID0gZmUodCk7IGZvciAodCBpbiB7IHN1Ym1pdDogITAsIHJlc2V0OiAhMCB9KSByLnBzZXVkb3NbdF0gPSBkZSh0KTsgZnVuY3Rpb24gdmUoKSB7IH0gdmUucHJvdG90eXBlID0gci5maWx0ZXJzID0gci5wc2V1ZG9zLCByLnNldEZpbHRlcnMgPSBuZXcgdmUsIGEgPSBvZS50b2tlbml6ZSA9IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCBpLCBvLCBhLCB1LCBzLCBsLCBjID0gTltlICsgIiAiXTsgaWYgKGMpIHJldHVybiB0ID8gMCA6IGMuc2xpY2UoMCk7IHUgPSBlLCBzID0gW10sIGwgPSByLnByZUZpbHRlcjsgd2hpbGUgKHUpIHsgbiAmJiAhKGkgPSBGLmV4ZWModSkpIHx8IChpICYmICh1ID0gdS5zbGljZShpWzBdLmxlbmd0aCkgfHwgdSksIHMucHVzaChvID0gW10pKSwgbiA9ICExLCAoaSA9IHouZXhlYyh1KSkgJiYgKG4gPSBpLnNoaWZ0KCksIG8ucHVzaCh7IHZhbHVlOiBuLCB0eXBlOiBpWzBdLnJlcGxhY2UoJCwgIiAiKSB9KSwgdSA9IHUuc2xpY2Uobi5sZW5ndGgpKTsgZm9yIChhIGluIHIuZmlsdGVyKSAhKGkgPSBYW2FdLmV4ZWModSkpIHx8IGxbYV0gJiYgIShpID0gbFthXShpKSkgfHwgKG4gPSBpLnNoaWZ0KCksIG8ucHVzaCh7IHZhbHVlOiBuLCB0eXBlOiBhLCBtYXRjaGVzOiBpIH0pLCB1ID0gdS5zbGljZShuLmxlbmd0aCkpOyBpZiAoIW4pIGJyZWFrIH0gcmV0dXJuIHQgPyB1Lmxlbmd0aCA6IHUgPyBvZS5lcnJvcihlKSA6IE4oZSwgcykuc2xpY2UoMCkgfTsgZnVuY3Rpb24geWUoZSkgeyBmb3IgKHZhciB0ID0gMCwgbiA9IGUubGVuZ3RoLCByID0gIiI7IHQgPCBuOyB0KyspciArPSBlW3RdLnZhbHVlOyByZXR1cm4gciB9IGZ1bmN0aW9uIG1lKGUsIHQsIG4pIHsgdmFyIHIgPSB0LmRpciwgaSA9IHQubmV4dCwgbyA9IGkgfHwgciwgYSA9IG4gJiYgInBhcmVudE5vZGUiID09PSBvLCB1ID0gVCsrOyByZXR1cm4gdC5maXJzdCA/IGZ1bmN0aW9uICh0LCBuLCBpKSB7IHdoaWxlICh0ID0gdFtyXSkgaWYgKDEgPT09IHQubm9kZVR5cGUgfHwgYSkgcmV0dXJuIGUodCwgbiwgaSk7IHJldHVybiAhMSB9IDogZnVuY3Rpb24gKHQsIG4sIHMpIHsgdmFyIGwsIGMsIGYsIGQgPSBbQywgdV07IGlmIChzKSB7IHdoaWxlICh0ID0gdFtyXSkgaWYgKCgxID09PSB0Lm5vZGVUeXBlIHx8IGEpICYmIGUodCwgbiwgcykpIHJldHVybiAhMCB9IGVsc2Ugd2hpbGUgKHQgPSB0W3JdKSBpZiAoMSA9PT0gdC5ub2RlVHlwZSB8fCBhKSBpZiAoZiA9IHRbeF0gfHwgKHRbeF0gPSB7fSksIGMgPSBmW3QudW5pcXVlSURdIHx8IChmW3QudW5pcXVlSURdID0ge30pLCBpICYmIGkgPT09IHQubm9kZU5hbWUudG9Mb3dlckNhc2UoKSkgdCA9IHRbcl0gfHwgdDsgZWxzZSB7IGlmICgobCA9IGNbb10pICYmIGxbMF0gPT09IEMgJiYgbFsxXSA9PT0gdSkgcmV0dXJuIGRbMl0gPSBsWzJdOyBpZiAoY1tvXSA9IGQsIGRbMl0gPSBlKHQsIG4sIHMpKSByZXR1cm4gITAgfSByZXR1cm4gITEgfSB9IGZ1bmN0aW9uIGJlKGUpIHsgcmV0dXJuIGUubGVuZ3RoID4gMSA/IGZ1bmN0aW9uICh0LCBuLCByKSB7IHZhciBpID0gZS5sZW5ndGg7IHdoaWxlIChpLS0pIGlmICghZVtpXSh0LCBuLCByKSkgcmV0dXJuICExOyByZXR1cm4gITAgfSA6IGVbMF0gfSBmdW5jdGlvbiB4ZShlLCB0LCBuKSB7IGZvciAodmFyIHIgPSAwLCBpID0gdC5sZW5ndGg7IHIgPCBpOyByKyspb2UoZSwgdFtyXSwgbik7IHJldHVybiBuIH0gZnVuY3Rpb24gd2UoZSwgdCwgbiwgciwgaSkgeyBmb3IgKHZhciBvLCBhID0gW10sIHUgPSAwLCBzID0gZS5sZW5ndGgsIGwgPSBudWxsICE9IHQ7IHUgPCBzOyB1KyspKG8gPSBlW3VdKSAmJiAobiAmJiAhbihvLCByLCBpKSB8fCAoYS5wdXNoKG8pLCBsICYmIHQucHVzaCh1KSkpOyByZXR1cm4gYSB9IGZ1bmN0aW9uIENlKGUsIHQsIG4sIHIsIGksIG8pIHsgcmV0dXJuIHIgJiYgIXJbeF0gJiYgKHIgPSBDZShyKSksIGkgJiYgIWlbeF0gJiYgKGkgPSBDZShpLCBvKSksIHVlKGZ1bmN0aW9uIChvLCBhLCB1LCBzKSB7IHZhciBsLCBjLCBmLCBkID0gW10sIHAgPSBbXSwgaCA9IGEubGVuZ3RoLCBnID0gbyB8fCB4ZSh0IHx8ICIqIiwgdS5ub2RlVHlwZSA/IFt1XSA6IHUsIFtdKSwgdiA9ICFlIHx8ICFvICYmIHQgPyBnIDogd2UoZywgZCwgZSwgdSwgcyksIHkgPSBuID8gaSB8fCAobyA/IGUgOiBoIHx8IHIpID8gW10gOiBhIDogdjsgaWYgKG4gJiYgbih2LCB5LCB1LCBzKSwgcikgeyBsID0gd2UoeSwgcCksIHIobCwgW10sIHUsIHMpLCBjID0gbC5sZW5ndGg7IHdoaWxlIChjLS0pIChmID0gbFtjXSkgJiYgKHlbcFtjXV0gPSAhKHZbcFtjXV0gPSBmKSkgfSBpZiAobykgeyBpZiAoaSB8fCBlKSB7IGlmIChpKSB7IGwgPSBbXSwgYyA9IHkubGVuZ3RoOyB3aGlsZSAoYy0tKSAoZiA9IHlbY10pICYmIGwucHVzaCh2W2NdID0gZik7IGkobnVsbCwgeSA9IFtdLCBsLCBzKSB9IGMgPSB5Lmxlbmd0aDsgd2hpbGUgKGMtLSkgKGYgPSB5W2NdKSAmJiAobCA9IGkgPyBQKG8sIGYpIDogZFtjXSkgPiAtMSAmJiAob1tsXSA9ICEoYVtsXSA9IGYpKSB9IH0gZWxzZSB5ID0gd2UoeSA9PT0gYSA/IHkuc3BsaWNlKGgsIHkubGVuZ3RoKSA6IHkpLCBpID8gaShudWxsLCBhLCB5LCBzKSA6IHEuYXBwbHkoYSwgeSkgfSkgfSBmdW5jdGlvbiBUZShlKSB7IGZvciAodmFyIHQsIG4sIGksIG8gPSBlLmxlbmd0aCwgYSA9IHIucmVsYXRpdmVbZVswXS50eXBlXSwgdSA9IGEgfHwgci5yZWxhdGl2ZVsiICJdLCBzID0gYSA/IDEgOiAwLCBjID0gbWUoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUgPT09IHQgfSwgdSwgITApLCBmID0gbWUoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIFAodCwgZSkgPiAtMSB9LCB1LCAhMCksIGQgPSBbZnVuY3Rpb24gKGUsIG4sIHIpIHsgdmFyIGkgPSAhYSAmJiAociB8fCBuICE9PSBsKSB8fCAoKHQgPSBuKS5ub2RlVHlwZSA/IGMoZSwgbiwgcikgOiBmKGUsIG4sIHIpKTsgcmV0dXJuIHQgPSBudWxsLCBpIH1dOyBzIDwgbzsgcysrKWlmIChuID0gci5yZWxhdGl2ZVtlW3NdLnR5cGVdKSBkID0gW21lKGJlKGQpLCBuKV07IGVsc2UgeyBpZiAoKG4gPSByLmZpbHRlcltlW3NdLnR5cGVdLmFwcGx5KG51bGwsIGVbc10ubWF0Y2hlcykpW3hdKSB7IGZvciAoaSA9ICsrczsgaSA8IG87IGkrKylpZiAoci5yZWxhdGl2ZVtlW2ldLnR5cGVdKSBicmVhazsgcmV0dXJuIENlKHMgPiAxICYmIGJlKGQpLCBzID4gMSAmJiB5ZShlLnNsaWNlKDAsIHMgLSAxKS5jb25jYXQoeyB2YWx1ZTogIiAiID09PSBlW3MgLSAyXS50eXBlID8gIioiIDogIiIgfSkpLnJlcGxhY2UoJCwgIiQxIiksIG4sIHMgPCBpICYmIFRlKGUuc2xpY2UocywgaSkpLCBpIDwgbyAmJiBUZShlID0gZS5zbGljZShpKSksIGkgPCBvICYmIHllKGUpKSB9IGQucHVzaChuKSB9IHJldHVybiBiZShkKSB9IGZ1bmN0aW9uIEVlKGUsIHQpIHsgdmFyIG4gPSB0Lmxlbmd0aCA+IDAsIGkgPSBlLmxlbmd0aCA+IDAsIG8gPSBmdW5jdGlvbiAobywgYSwgdSwgcywgYykgeyB2YXIgZiwgaCwgdiwgeSA9IDAsIG0gPSAiMCIsIGIgPSBvICYmIFtdLCB4ID0gW10sIHcgPSBsLCBUID0gbyB8fCBpICYmIHIuZmluZC5UQUcoIioiLCBjKSwgRSA9IEMgKz0gbnVsbCA9PSB3ID8gMSA6IE1hdGgucmFuZG9tKCkgfHwgLjEsIE4gPSBULmxlbmd0aDsgZm9yIChjICYmIChsID0gYSA9PT0gcCB8fCBhIHx8IGMpOyBtICE9PSBOICYmIG51bGwgIT0gKGYgPSBUW21dKTsgbSsrKSB7IGlmIChpICYmIGYpIHsgaCA9IDAsIGEgfHwgZi5vd25lckRvY3VtZW50ID09PSBwIHx8IChkKGYpLCB1ID0gIWcpOyB3aGlsZSAodiA9IGVbaCsrXSkgaWYgKHYoZiwgYSB8fCBwLCB1KSkgeyBzLnB1c2goZik7IGJyZWFrIH0gYyAmJiAoQyA9IEUpIH0gbiAmJiAoKGYgPSAhdiAmJiBmKSAmJiB5LS0gLCBvICYmIGIucHVzaChmKSkgfSBpZiAoeSArPSBtLCBuICYmIG0gIT09IHkpIHsgaCA9IDA7IHdoaWxlICh2ID0gdFtoKytdKSB2KGIsIHgsIGEsIHUpOyBpZiAobykgeyBpZiAoeSA+IDApIHdoaWxlIChtLS0pIGJbbV0gfHwgeFttXSB8fCAoeFttXSA9IEwuY2FsbChzKSk7IHggPSB3ZSh4KSB9IHEuYXBwbHkocywgeCksIGMgJiYgIW8gJiYgeC5sZW5ndGggPiAwICYmIHkgKyB0Lmxlbmd0aCA+IDEgJiYgb2UudW5pcXVlU29ydChzKSB9IHJldHVybiBjICYmIChDID0gRSwgbCA9IHcpLCBiIH07IHJldHVybiBuID8gdWUobykgOiBvIH0gcmV0dXJuIHUgPSBvZS5jb21waWxlID0gZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIgPSBbXSwgaSA9IFtdLCBvID0ga1tlICsgIiAiXTsgaWYgKCFvKSB7IHQgfHwgKHQgPSBhKGUpKSwgbiA9IHQubGVuZ3RoOyB3aGlsZSAobi0tKSAobyA9IFRlKHRbbl0pKVt4XSA/IHIucHVzaChvKSA6IGkucHVzaChvKTsgKG8gPSBrKGUsIEVlKGksIHIpKSkuc2VsZWN0b3IgPSBlIH0gcmV0dXJuIG8gfSwgcyA9IG9lLnNlbGVjdCA9IGZ1bmN0aW9uIChlLCB0LCBuLCBpKSB7IHZhciBvLCBzLCBsLCBjLCBmLCBkID0gImZ1bmN0aW9uIiA9PSB0eXBlb2YgZSAmJiBlLCBwID0gIWkgJiYgYShlID0gZC5zZWxlY3RvciB8fCBlKTsgaWYgKG4gPSBuIHx8IFtdLCAxID09PSBwLmxlbmd0aCkgeyBpZiAoKHMgPSBwWzBdID0gcFswXS5zbGljZSgwKSkubGVuZ3RoID4gMiAmJiAiSUQiID09PSAobCA9IHNbMF0pLnR5cGUgJiYgOSA9PT0gdC5ub2RlVHlwZSAmJiBnICYmIHIucmVsYXRpdmVbc1sxXS50eXBlXSkgeyBpZiAoISh0ID0gKHIuZmluZC5JRChsLm1hdGNoZXNbMF0ucmVwbGFjZShaLCBlZSksIHQpIHx8IFtdKVswXSkpIHJldHVybiBuOyBkICYmICh0ID0gdC5wYXJlbnROb2RlKSwgZSA9IGUuc2xpY2Uocy5zaGlmdCgpLnZhbHVlLmxlbmd0aCkgfSBvID0gWC5uZWVkc0NvbnRleHQudGVzdChlKSA/IDAgOiBzLmxlbmd0aDsgd2hpbGUgKG8tLSkgeyBpZiAobCA9IHNbb10sIHIucmVsYXRpdmVbYyA9IGwudHlwZV0pIGJyZWFrOyBpZiAoKGYgPSByLmZpbmRbY10pICYmIChpID0gZihsLm1hdGNoZXNbMF0ucmVwbGFjZShaLCBlZSksIEoudGVzdChzWzBdLnR5cGUpICYmIGdlKHQucGFyZW50Tm9kZSkgfHwgdCkpKSB7IGlmIChzLnNwbGljZShvLCAxKSwgIShlID0gaS5sZW5ndGggJiYgeWUocykpKSByZXR1cm4gcS5hcHBseShuLCBpKSwgbjsgYnJlYWsgfSB9IH0gcmV0dXJuIChkIHx8IHUoZSwgcCkpKGksIHQsICFnLCBuLCAhdCB8fCBKLnRlc3QoZSkgJiYgZ2UodC5wYXJlbnROb2RlKSB8fCB0KSwgbiB9LCBuLnNvcnRTdGFibGUgPSB4LnNwbGl0KCIiKS5zb3J0KEEpLmpvaW4oIiIpID09PSB4LCBuLmRldGVjdER1cGxpY2F0ZXMgPSAhIWYsIGQoKSwgbi5zb3J0RGV0YWNoZWQgPSBzZShmdW5jdGlvbiAoZSkgeyByZXR1cm4gMSAmIGUuY29tcGFyZURvY3VtZW50UG9zaXRpb24ocC5jcmVhdGVFbGVtZW50KCJmaWVsZHNldCIpKSB9KSwgc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUuaW5uZXJIVE1MID0gIjxhIGhyZWY9JyMnPjwvYT4iLCAiIyIgPT09IGUuZmlyc3RDaGlsZC5nZXRBdHRyaWJ1dGUoImhyZWYiKSB9KSB8fCBsZSgidHlwZXxocmVmfGhlaWdodHx3aWR0aCIsIGZ1bmN0aW9uIChlLCB0LCBuKSB7IGlmICghbikgcmV0dXJuIGUuZ2V0QXR0cmlidXRlKHQsICJ0eXBlIiA9PT0gdC50b0xvd2VyQ2FzZSgpID8gMSA6IDIpIH0pLCBuLmF0dHJpYnV0ZXMgJiYgc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUuaW5uZXJIVE1MID0gIjxpbnB1dC8+IiwgZS5maXJzdENoaWxkLnNldEF0dHJpYnV0ZSgidmFsdWUiLCAiIiksICIiID09PSBlLmZpcnN0Q2hpbGQuZ2V0QXR0cmlidXRlKCJ2YWx1ZSIpIH0pIHx8IGxlKCJ2YWx1ZSIsIGZ1bmN0aW9uIChlLCB0LCBuKSB7IGlmICghbiAmJiAiaW5wdXQiID09PSBlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkpIHJldHVybiBlLmRlZmF1bHRWYWx1ZSB9KSwgc2UoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIG51bGwgPT0gZS5nZXRBdHRyaWJ1dGUoImRpc2FibGVkIikgfSkgfHwgbGUoSCwgZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHI7IGlmICghbikgcmV0dXJuICEwID09PSBlW3RdID8gdC50b0xvd2VyQ2FzZSgpIDogKHIgPSBlLmdldEF0dHJpYnV0ZU5vZGUodCkpICYmIHIuc3BlY2lmaWVkID8gci52YWx1ZSA6IG51bGwgfSksIG9lIH0oZSk7IHcuZmluZCA9IEUsIHcuZXhwciA9IEUuc2VsZWN0b3JzLCB3LmV4cHJbIjoiXSA9IHcuZXhwci5wc2V1ZG9zLCB3LnVuaXF1ZVNvcnQgPSB3LnVuaXF1ZSA9IEUudW5pcXVlU29ydCwgdy50ZXh0ID0gRS5nZXRUZXh0LCB3LmlzWE1MRG9jID0gRS5pc1hNTCwgdy5jb250YWlucyA9IEUuY29udGFpbnMsIHcuZXNjYXBlU2VsZWN0b3IgPSBFLmVzY2FwZTsgdmFyIE4gPSBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciA9IFtdLCBpID0gdm9pZCAwICE9PSBuOyB3aGlsZSAoKGUgPSBlW3RdKSAmJiA5ICE9PSBlLm5vZGVUeXBlKSBpZiAoMSA9PT0gZS5ub2RlVHlwZSkgeyBpZiAoaSAmJiB3KGUpLmlzKG4pKSBicmVhazsgci5wdXNoKGUpIH0gcmV0dXJuIHIgfSwgayA9IGZ1bmN0aW9uIChlLCB0KSB7IGZvciAodmFyIG4gPSBbXTsgZTsgZSA9IGUubmV4dFNpYmxpbmcpMSA9PT0gZS5ub2RlVHlwZSAmJiBlICE9PSB0ICYmIG4ucHVzaChlKTsgcmV0dXJuIG4gfSwgQSA9IHcuZXhwci5tYXRjaC5uZWVkc0NvbnRleHQ7IGZ1bmN0aW9uIEQoZSwgdCkgeyByZXR1cm4gZS5ub2RlTmFtZSAmJiBlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IHQudG9Mb3dlckNhc2UoKSB9IHZhciBTID0gL148KFthLXpdW15cL1wwPjpceDIwXHRcclxuXGZdKilbXHgyMFx0XHJcblxmXSpcLz8+KD86PFwvXDE+fCkkL2k7IGZ1bmN0aW9uIEwoZSwgdCwgbikgeyByZXR1cm4gZyh0KSA/IHcuZ3JlcChlLCBmdW5jdGlvbiAoZSwgcikgeyByZXR1cm4gISF0LmNhbGwoZSwgciwgZSkgIT09IG4gfSkgOiB0Lm5vZGVUeXBlID8gdy5ncmVwKGUsIGZ1bmN0aW9uIChlKSB7IHJldHVybiBlID09PSB0ICE9PSBuIH0pIDogInN0cmluZyIgIT0gdHlwZW9mIHQgPyB3LmdyZXAoZSwgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHMuY2FsbCh0LCBlKSA+IC0xICE9PSBuIH0pIDogdy5maWx0ZXIodCwgZSwgbikgfSB3LmZpbHRlciA9IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHZhciByID0gdFswXTsgcmV0dXJuIG4gJiYgKGUgPSAiOm5vdCgiICsgZSArICIpIiksIDEgPT09IHQubGVuZ3RoICYmIDEgPT09IHIubm9kZVR5cGUgPyB3LmZpbmQubWF0Y2hlc1NlbGVjdG9yKHIsIGUpID8gW3JdIDogW10gOiB3LmZpbmQubWF0Y2hlcyhlLCB3LmdyZXAodCwgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIDEgPT09IGUubm9kZVR5cGUgfSkpIH0sIHcuZm4uZXh0ZW5kKHsgZmluZDogZnVuY3Rpb24gKGUpIHsgdmFyIHQsIG4sIHIgPSB0aGlzLmxlbmd0aCwgaSA9IHRoaXM7IGlmICgic3RyaW5nIiAhPSB0eXBlb2YgZSkgcmV0dXJuIHRoaXMucHVzaFN0YWNrKHcoZSkuZmlsdGVyKGZ1bmN0aW9uICgpIHsgZm9yICh0ID0gMDsgdCA8IHI7IHQrKylpZiAody5jb250YWlucyhpW3RdLCB0aGlzKSkgcmV0dXJuICEwIH0pKTsgZm9yIChuID0gdGhpcy5wdXNoU3RhY2soW10pLCB0ID0gMDsgdCA8IHI7IHQrKyl3LmZpbmQoZSwgaVt0XSwgbik7IHJldHVybiByID4gMSA/IHcudW5pcXVlU29ydChuKSA6IG4gfSwgZmlsdGVyOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5wdXNoU3RhY2soTCh0aGlzLCBlIHx8IFtdLCAhMSkpIH0sIG5vdDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHRoaXMucHVzaFN0YWNrKEwodGhpcywgZSB8fCBbXSwgITApKSB9LCBpczogZnVuY3Rpb24gKGUpIHsgcmV0dXJuICEhTCh0aGlzLCAic3RyaW5nIiA9PSB0eXBlb2YgZSAmJiBBLnRlc3QoZSkgPyB3KGUpIDogZSB8fCBbXSwgITEpLmxlbmd0aCB9IH0pOyB2YXIgaiwgcSA9IC9eKD86XHMqKDxbXHdcV10rPilbXj5dKnwjKFtcdy1dKykpJC87ICh3LmZuLmluaXQgPSBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgaSwgbzsgaWYgKCFlKSByZXR1cm4gdGhpczsgaWYgKG4gPSBuIHx8IGosICJzdHJpbmciID09IHR5cGVvZiBlKSB7IGlmICghKGkgPSAiPCIgPT09IGVbMF0gJiYgIj4iID09PSBlW2UubGVuZ3RoIC0gMV0gJiYgZS5sZW5ndGggPj0gMyA/IFtudWxsLCBlLCBudWxsXSA6IHEuZXhlYyhlKSkgfHwgIWlbMV0gJiYgdCkgcmV0dXJuICF0IHx8IHQuanF1ZXJ5ID8gKHQgfHwgbikuZmluZChlKSA6IHRoaXMuY29uc3RydWN0b3IodCkuZmluZChlKTsgaWYgKGlbMV0pIHsgaWYgKHQgPSB0IGluc3RhbmNlb2YgdyA/IHRbMF0gOiB0LCB3Lm1lcmdlKHRoaXMsIHcucGFyc2VIVE1MKGlbMV0sIHQgJiYgdC5ub2RlVHlwZSA/IHQub3duZXJEb2N1bWVudCB8fCB0IDogciwgITApKSwgUy50ZXN0KGlbMV0pICYmIHcuaXNQbGFpbk9iamVjdCh0KSkgZm9yIChpIGluIHQpIGcodGhpc1tpXSkgPyB0aGlzW2ldKHRbaV0pIDogdGhpcy5hdHRyKGksIHRbaV0pOyByZXR1cm4gdGhpcyB9IHJldHVybiAobyA9IHIuZ2V0RWxlbWVudEJ5SWQoaVsyXSkpICYmICh0aGlzWzBdID0gbywgdGhpcy5sZW5ndGggPSAxKSwgdGhpcyB9IHJldHVybiBlLm5vZGVUeXBlID8gKHRoaXNbMF0gPSBlLCB0aGlzLmxlbmd0aCA9IDEsIHRoaXMpIDogZyhlKSA/IHZvaWQgMCAhPT0gbi5yZWFkeSA/IG4ucmVhZHkoZSkgOiBlKHcpIDogdy5tYWtlQXJyYXkoZSwgdGhpcykgfSkucHJvdG90eXBlID0gdy5mbiwgaiA9IHcocik7IHZhciBPID0gL14oPzpwYXJlbnRzfHByZXYoPzpVbnRpbHxBbGwpKS8sIFAgPSB7IGNoaWxkcmVuOiAhMCwgY29udGVudHM6ICEwLCBuZXh0OiAhMCwgcHJldjogITAgfTsgdy5mbi5leHRlbmQoeyBoYXM6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gdyhlLCB0aGlzKSwgbiA9IHQubGVuZ3RoOyByZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24gKCkgeyBmb3IgKHZhciBlID0gMDsgZSA8IG47IGUrKylpZiAody5jb250YWlucyh0aGlzLCB0W2VdKSkgcmV0dXJuICEwIH0pIH0sIGNsb3Nlc3Q6IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCByID0gMCwgaSA9IHRoaXMubGVuZ3RoLCBvID0gW10sIGEgPSAic3RyaW5nIiAhPSB0eXBlb2YgZSAmJiB3KGUpOyBpZiAoIUEudGVzdChlKSkgZm9yICg7IHIgPCBpOyByKyspZm9yIChuID0gdGhpc1tyXTsgbiAmJiBuICE9PSB0OyBuID0gbi5wYXJlbnROb2RlKWlmIChuLm5vZGVUeXBlIDwgMTEgJiYgKGEgPyBhLmluZGV4KG4pID4gLTEgOiAxID09PSBuLm5vZGVUeXBlICYmIHcuZmluZC5tYXRjaGVzU2VsZWN0b3IobiwgZSkpKSB7IG8ucHVzaChuKTsgYnJlYWsgfSByZXR1cm4gdGhpcy5wdXNoU3RhY2soby5sZW5ndGggPiAxID8gdy51bmlxdWVTb3J0KG8pIDogbykgfSwgaW5kZXg6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBlID8gInN0cmluZyIgPT0gdHlwZW9mIGUgPyBzLmNhbGwodyhlKSwgdGhpc1swXSkgOiBzLmNhbGwodGhpcywgZS5qcXVlcnkgPyBlWzBdIDogZSkgOiB0aGlzWzBdICYmIHRoaXNbMF0ucGFyZW50Tm9kZSA/IHRoaXMuZmlyc3QoKS5wcmV2QWxsKCkubGVuZ3RoIDogLTEgfSwgYWRkOiBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gdGhpcy5wdXNoU3RhY2sody51bmlxdWVTb3J0KHcubWVyZ2UodGhpcy5nZXQoKSwgdyhlLCB0KSkpKSB9LCBhZGRCYWNrOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5hZGQobnVsbCA9PSBlID8gdGhpcy5wcmV2T2JqZWN0IDogdGhpcy5wcmV2T2JqZWN0LmZpbHRlcihlKSkgfSB9KTsgZnVuY3Rpb24gSChlLCB0KSB7IHdoaWxlICgoZSA9IGVbdF0pICYmIDEgIT09IGUubm9kZVR5cGUpOyByZXR1cm4gZSB9IHcuZWFjaCh7IHBhcmVudDogZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSBlLnBhcmVudE5vZGU7IHJldHVybiB0ICYmIDExICE9PSB0Lm5vZGVUeXBlID8gdCA6IG51bGwgfSwgcGFyZW50czogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIE4oZSwgInBhcmVudE5vZGUiKSB9LCBwYXJlbnRzVW50aWw6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBOKGUsICJwYXJlbnROb2RlIiwgbikgfSwgbmV4dDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEgoZSwgIm5leHRTaWJsaW5nIikgfSwgcHJldjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEgoZSwgInByZXZpb3VzU2libGluZyIpIH0sIG5leHRBbGw6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBOKGUsICJuZXh0U2libGluZyIpIH0sIHByZXZBbGw6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBOKGUsICJwcmV2aW91c1NpYmxpbmciKSB9LCBuZXh0VW50aWw6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBOKGUsICJuZXh0U2libGluZyIsIG4pIH0sIHByZXZVbnRpbDogZnVuY3Rpb24gKGUsIHQsIG4pIHsgcmV0dXJuIE4oZSwgInByZXZpb3VzU2libGluZyIsIG4pIH0sIHNpYmxpbmdzOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gaygoZS5wYXJlbnROb2RlIHx8IHt9KS5maXJzdENoaWxkLCBlKSB9LCBjaGlsZHJlbjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGsoZS5maXJzdENoaWxkKSB9LCBjb250ZW50czogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEQoZSwgImlmcmFtZSIpID8gZS5jb250ZW50RG9jdW1lbnQgOiAoRChlLCAidGVtcGxhdGUiKSAmJiAoZSA9IGUuY29udGVudCB8fCBlKSwgdy5tZXJnZShbXSwgZS5jaGlsZE5vZGVzKSkgfSB9LCBmdW5jdGlvbiAoZSwgdCkgeyB3LmZuW2VdID0gZnVuY3Rpb24gKG4sIHIpIHsgdmFyIGkgPSB3Lm1hcCh0aGlzLCB0LCBuKTsgcmV0dXJuICJVbnRpbCIgIT09IGUuc2xpY2UoLTUpICYmIChyID0gbiksIHIgJiYgInN0cmluZyIgPT0gdHlwZW9mIHIgJiYgKGkgPSB3LmZpbHRlcihyLCBpKSksIHRoaXMubGVuZ3RoID4gMSAmJiAoUFtlXSB8fCB3LnVuaXF1ZVNvcnQoaSksIE8udGVzdChlKSAmJiBpLnJldmVyc2UoKSksIHRoaXMucHVzaFN0YWNrKGkpIH0gfSk7IHZhciBJID0gL1teXHgyMFx0XHJcblxmXSsvZzsgZnVuY3Rpb24gUihlKSB7IHZhciB0ID0ge307IHJldHVybiB3LmVhY2goZS5tYXRjaChJKSB8fCBbXSwgZnVuY3Rpb24gKGUsIG4pIHsgdFtuXSA9ICEwIH0pLCB0IH0gdy5DYWxsYmFja3MgPSBmdW5jdGlvbiAoZSkgeyBlID0gInN0cmluZyIgPT0gdHlwZW9mIGUgPyBSKGUpIDogdy5leHRlbmQoe30sIGUpOyB2YXIgdCwgbiwgciwgaSwgbyA9IFtdLCBhID0gW10sIHUgPSAtMSwgcyA9IGZ1bmN0aW9uICgpIHsgZm9yIChpID0gaSB8fCBlLm9uY2UsIHIgPSB0ID0gITA7IGEubGVuZ3RoOyB1ID0gLTEpIHsgbiA9IGEuc2hpZnQoKTsgd2hpbGUgKCsrdSA8IG8ubGVuZ3RoKSAhMSA9PT0gb1t1XS5hcHBseShuWzBdLCBuWzFdKSAmJiBlLnN0b3BPbkZhbHNlICYmICh1ID0gby5sZW5ndGgsIG4gPSAhMSkgfSBlLm1lbW9yeSB8fCAobiA9ICExKSwgdCA9ICExLCBpICYmIChvID0gbiA/IFtdIDogIiIpIH0sIGwgPSB7IGFkZDogZnVuY3Rpb24gKCkgeyByZXR1cm4gbyAmJiAobiAmJiAhdCAmJiAodSA9IG8ubGVuZ3RoIC0gMSwgYS5wdXNoKG4pKSwgZnVuY3Rpb24gdChuKSB7IHcuZWFjaChuLCBmdW5jdGlvbiAobiwgcikgeyBnKHIpID8gZS51bmlxdWUgJiYgbC5oYXMocikgfHwgby5wdXNoKHIpIDogciAmJiByLmxlbmd0aCAmJiAic3RyaW5nIiAhPT0gYihyKSAmJiB0KHIpIH0pIH0oYXJndW1lbnRzKSwgbiAmJiAhdCAmJiBzKCkpLCB0aGlzIH0sIHJlbW92ZTogZnVuY3Rpb24gKCkgeyByZXR1cm4gdy5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG47IHdoaWxlICgobiA9IHcuaW5BcnJheSh0LCBvLCBuKSkgPiAtMSkgby5zcGxpY2UobiwgMSksIG4gPD0gdSAmJiB1LS0gfSksIHRoaXMgfSwgaGFzOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZSA/IHcuaW5BcnJheShlLCBvKSA+IC0xIDogby5sZW5ndGggPiAwIH0sIGVtcHR5OiBmdW5jdGlvbiAoKSB7IHJldHVybiBvICYmIChvID0gW10pLCB0aGlzIH0sIGRpc2FibGU6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGkgPSBhID0gW10sIG8gPSBuID0gIiIsIHRoaXMgfSwgZGlzYWJsZWQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuICFvIH0sIGxvY2s6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGkgPSBhID0gW10sIG4gfHwgdCB8fCAobyA9IG4gPSAiIiksIHRoaXMgfSwgbG9ja2VkOiBmdW5jdGlvbiAoKSB7IHJldHVybiAhIWkgfSwgZmlyZVdpdGg6IGZ1bmN0aW9uIChlLCBuKSB7IHJldHVybiBpIHx8IChuID0gW2UsIChuID0gbiB8fCBbXSkuc2xpY2UgPyBuLnNsaWNlKCkgOiBuXSwgYS5wdXNoKG4pLCB0IHx8IHMoKSksIHRoaXMgfSwgZmlyZTogZnVuY3Rpb24gKCkgeyByZXR1cm4gbC5maXJlV2l0aCh0aGlzLCBhcmd1bWVudHMpLCB0aGlzIH0sIGZpcmVkOiBmdW5jdGlvbiAoKSB7IHJldHVybiAhIXIgfSB9OyByZXR1cm4gbCB9OyBmdW5jdGlvbiBCKGUpIHsgcmV0dXJuIGUgfSBmdW5jdGlvbiBNKGUpIHsgdGhyb3cgZSB9IGZ1bmN0aW9uIFcoZSwgdCwgbiwgcikgeyB2YXIgaTsgdHJ5IHsgZSAmJiBnKGkgPSBlLnByb21pc2UpID8gaS5jYWxsKGUpLmRvbmUodCkuZmFpbChuKSA6IGUgJiYgZyhpID0gZS50aGVuKSA/IGkuY2FsbChlLCB0LCBuKSA6IHQuYXBwbHkodm9pZCAwLCBbZV0uc2xpY2UocikpIH0gY2F0Y2ggKGUpIHsgbi5hcHBseSh2b2lkIDAsIFtlXSkgfSB9IHcuZXh0ZW5kKHsgRGVmZXJyZWQ6IGZ1bmN0aW9uICh0KSB7IHZhciBuID0gW1sibm90aWZ5IiwgInByb2dyZXNzIiwgdy5DYWxsYmFja3MoIm1lbW9yeSIpLCB3LkNhbGxiYWNrcygibWVtb3J5IiksIDJdLCBbInJlc29sdmUiLCAiZG9uZSIsIHcuQ2FsbGJhY2tzKCJvbmNlIG1lbW9yeSIpLCB3LkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSwgMCwgInJlc29sdmVkIl0sIFsicmVqZWN0IiwgImZhaWwiLCB3LkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSwgdy5DYWxsYmFja3MoIm9uY2UgbWVtb3J5IiksIDEsICJyZWplY3RlZCJdXSwgciA9ICJwZW5kaW5nIiwgaSA9IHsgc3RhdGU6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHIgfSwgYWx3YXlzOiBmdW5jdGlvbiAoKSB7IHJldHVybiBvLmRvbmUoYXJndW1lbnRzKS5mYWlsKGFyZ3VtZW50cyksIHRoaXMgfSwgImNhdGNoIjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGkudGhlbihudWxsLCBlKSB9LCBwaXBlOiBmdW5jdGlvbiAoKSB7IHZhciBlID0gYXJndW1lbnRzOyByZXR1cm4gdy5EZWZlcnJlZChmdW5jdGlvbiAodCkgeyB3LmVhY2gobiwgZnVuY3Rpb24gKG4sIHIpIHsgdmFyIGkgPSBnKGVbcls0XV0pICYmIGVbcls0XV07IG9bclsxXV0oZnVuY3Rpb24gKCkgeyB2YXIgZSA9IGkgJiYgaS5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyBlICYmIGcoZS5wcm9taXNlKSA/IGUucHJvbWlzZSgpLnByb2dyZXNzKHQubm90aWZ5KS5kb25lKHQucmVzb2x2ZSkuZmFpbCh0LnJlamVjdCkgOiB0W3JbMF0gKyAiV2l0aCJdKHRoaXMsIGkgPyBbZV0gOiBhcmd1bWVudHMpIH0pIH0pLCBlID0gbnVsbCB9KS5wcm9taXNlKCkgfSwgdGhlbjogZnVuY3Rpb24gKHQsIHIsIGkpIHsgdmFyIG8gPSAwOyBmdW5jdGlvbiBhKHQsIG4sIHIsIGkpIHsgcmV0dXJuIGZ1bmN0aW9uICgpIHsgdmFyIHUgPSB0aGlzLCBzID0gYXJndW1lbnRzLCBsID0gZnVuY3Rpb24gKCkgeyB2YXIgZSwgbDsgaWYgKCEodCA8IG8pKSB7IGlmICgoZSA9IHIuYXBwbHkodSwgcykpID09PSBuLnByb21pc2UoKSkgdGhyb3cgbmV3IFR5cGVFcnJvcigiVGhlbmFibGUgc2VsZi1yZXNvbHV0aW9uIik7IGwgPSBlICYmICgib2JqZWN0IiA9PSB0eXBlb2YgZSB8fCAiZnVuY3Rpb24iID09IHR5cGVvZiBlKSAmJiBlLnRoZW4sIGcobCkgPyBpID8gbC5jYWxsKGUsIGEobywgbiwgQiwgaSksIGEobywgbiwgTSwgaSkpIDogKG8rKyAsIGwuY2FsbChlLCBhKG8sIG4sIEIsIGkpLCBhKG8sIG4sIE0sIGkpLCBhKG8sIG4sIEIsIG4ubm90aWZ5V2l0aCkpKSA6IChyICE9PSBCICYmICh1ID0gdm9pZCAwLCBzID0gW2VdKSwgKGkgfHwgbi5yZXNvbHZlV2l0aCkodSwgcykpIH0gfSwgYyA9IGkgPyBsIDogZnVuY3Rpb24gKCkgeyB0cnkgeyBsKCkgfSBjYXRjaCAoZSkgeyB3LkRlZmVycmVkLmV4Y2VwdGlvbkhvb2sgJiYgdy5EZWZlcnJlZC5leGNlcHRpb25Ib29rKGUsIGMuc3RhY2tUcmFjZSksIHQgKyAxID49IG8gJiYgKHIgIT09IE0gJiYgKHUgPSB2b2lkIDAsIHMgPSBbZV0pLCBuLnJlamVjdFdpdGgodSwgcykpIH0gfTsgdCA/IGMoKSA6ICh3LkRlZmVycmVkLmdldFN0YWNrSG9vayAmJiAoYy5zdGFja1RyYWNlID0gdy5EZWZlcnJlZC5nZXRTdGFja0hvb2soKSksIGUuc2V0VGltZW91dChjKSkgfSB9IHJldHVybiB3LkRlZmVycmVkKGZ1bmN0aW9uIChlKSB7IG5bMF1bM10uYWRkKGEoMCwgZSwgZyhpKSA/IGkgOiBCLCBlLm5vdGlmeVdpdGgpKSwgblsxXVszXS5hZGQoYSgwLCBlLCBnKHQpID8gdCA6IEIpKSwgblsyXVszXS5hZGQoYSgwLCBlLCBnKHIpID8gciA6IE0pKSB9KS5wcm9taXNlKCkgfSwgcHJvbWlzZTogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIG51bGwgIT0gZSA/IHcuZXh0ZW5kKGUsIGkpIDogaSB9IH0sIG8gPSB7fTsgcmV0dXJuIHcuZWFjaChuLCBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgYSA9IHRbMl0sIHUgPSB0WzVdOyBpW3RbMV1dID0gYS5hZGQsIHUgJiYgYS5hZGQoZnVuY3Rpb24gKCkgeyByID0gdSB9LCBuWzMgLSBlXVsyXS5kaXNhYmxlLCBuWzMgLSBlXVszXS5kaXNhYmxlLCBuWzBdWzJdLmxvY2ssIG5bMF1bM10ubG9jayksIGEuYWRkKHRbM10uZmlyZSksIG9bdFswXV0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiBvW3RbMF0gKyAiV2l0aCJdKHRoaXMgPT09IG8gPyB2b2lkIDAgOiB0aGlzLCBhcmd1bWVudHMpLCB0aGlzIH0sIG9bdFswXSArICJXaXRoIl0gPSBhLmZpcmVXaXRoIH0pLCBpLnByb21pc2UobyksIHQgJiYgdC5jYWxsKG8sIG8pLCBvIH0sIHdoZW46IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gYXJndW1lbnRzLmxlbmd0aCwgbiA9IHQsIHIgPSBBcnJheShuKSwgaSA9IG8uY2FsbChhcmd1bWVudHMpLCBhID0gdy5EZWZlcnJlZCgpLCB1ID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGZ1bmN0aW9uIChuKSB7IHJbZV0gPSB0aGlzLCBpW2VdID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgPyBvLmNhbGwoYXJndW1lbnRzKSA6IG4sIC0tdCB8fCBhLnJlc29sdmVXaXRoKHIsIGkpIH0gfTsgaWYgKHQgPD0gMSAmJiAoVyhlLCBhLmRvbmUodShuKSkucmVzb2x2ZSwgYS5yZWplY3QsICF0KSwgInBlbmRpbmciID09PSBhLnN0YXRlKCkgfHwgZyhpW25dICYmIGlbbl0udGhlbikpKSByZXR1cm4gYS50aGVuKCk7IHdoaWxlIChuLS0pIFcoaVtuXSwgdShuKSwgYS5yZWplY3QpOyByZXR1cm4gYS5wcm9taXNlKCkgfSB9KTsgdmFyICQgPSAvXihFdmFsfEludGVybmFsfFJhbmdlfFJlZmVyZW5jZXxTeW50YXh8VHlwZXxVUkkpRXJyb3IkLzsgdy5EZWZlcnJlZC5leGNlcHRpb25Ib29rID0gZnVuY3Rpb24gKHQsIG4pIHsgZS5jb25zb2xlICYmIGUuY29uc29sZS53YXJuICYmIHQgJiYgJC50ZXN0KHQubmFtZSkgJiYgZS5jb25zb2xlLndhcm4oImpRdWVyeS5EZWZlcnJlZCBleGNlcHRpb246ICIgKyB0Lm1lc3NhZ2UsIHQuc3RhY2ssIG4pIH0sIHcucmVhZHlFeGNlcHRpb24gPSBmdW5jdGlvbiAodCkgeyBlLnNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyB0aHJvdyB0IH0pIH07IHZhciBGID0gdy5EZWZlcnJlZCgpOyB3LmZuLnJlYWR5ID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEYudGhlbihlKVsiY2F0Y2giXShmdW5jdGlvbiAoZSkgeyB3LnJlYWR5RXhjZXB0aW9uKGUpIH0pLCB0aGlzIH0sIHcuZXh0ZW5kKHsgaXNSZWFkeTogITEsIHJlYWR5V2FpdDogMSwgcmVhZHk6IGZ1bmN0aW9uIChlKSB7ICghMCA9PT0gZSA/IC0tdy5yZWFkeVdhaXQgOiB3LmlzUmVhZHkpIHx8ICh3LmlzUmVhZHkgPSAhMCwgITAgIT09IGUgJiYgLS13LnJlYWR5V2FpdCA+IDAgfHwgRi5yZXNvbHZlV2l0aChyLCBbd10pKSB9IH0pLCB3LnJlYWR5LnRoZW4gPSBGLnRoZW47IGZ1bmN0aW9uIHooKSB7IHIucmVtb3ZlRXZlbnRMaXN0ZW5lcigiRE9NQ29udGVudExvYWRlZCIsIHopLCBlLnJlbW92ZUV2ZW50TGlzdGVuZXIoImxvYWQiLCB6KSwgdy5yZWFkeSgpIH0gImNvbXBsZXRlIiA9PT0gci5yZWFkeVN0YXRlIHx8ICJsb2FkaW5nIiAhPT0gci5yZWFkeVN0YXRlICYmICFyLmRvY3VtZW50RWxlbWVudC5kb1Njcm9sbCA/IGUuc2V0VGltZW91dCh3LnJlYWR5KSA6IChyLmFkZEV2ZW50TGlzdGVuZXIoIkRPTUNvbnRlbnRMb2FkZWQiLCB6KSwgZS5hZGRFdmVudExpc3RlbmVyKCJsb2FkIiwgeikpOyB2YXIgXyA9IGZ1bmN0aW9uIChlLCB0LCBuLCByLCBpLCBvLCBhKSB7IHZhciB1ID0gMCwgcyA9IGUubGVuZ3RoLCBsID0gbnVsbCA9PSBuOyBpZiAoIm9iamVjdCIgPT09IGIobikpIHsgaSA9ICEwOyBmb3IgKHUgaW4gbikgXyhlLCB0LCB1LCBuW3VdLCAhMCwgbywgYSkgfSBlbHNlIGlmICh2b2lkIDAgIT09IHIgJiYgKGkgPSAhMCwgZyhyKSB8fCAoYSA9ICEwKSwgbCAmJiAoYSA/ICh0LmNhbGwoZSwgciksIHQgPSBudWxsKSA6IChsID0gdCwgdCA9IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiBsLmNhbGwodyhlKSwgbikgfSkpLCB0KSkgZm9yICg7IHUgPCBzOyB1KyspdChlW3VdLCBuLCBhID8gciA6IHIuY2FsbChlW3VdLCB1LCB0KGVbdV0sIG4pKSk7IHJldHVybiBpID8gZSA6IGwgPyB0LmNhbGwoZSkgOiBzID8gdChlWzBdLCBuKSA6IG8gfSwgVSA9IC9eLW1zLS8sIFYgPSAvLShbYS16XSkvZzsgZnVuY3Rpb24gWChlLCB0KSB7IHJldHVybiB0LnRvVXBwZXJDYXNlKCkgfSBmdW5jdGlvbiBRKGUpIHsgcmV0dXJuIGUucmVwbGFjZShVLCAibXMtIikucmVwbGFjZShWLCBYKSB9IHZhciBZID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuIDEgPT09IGUubm9kZVR5cGUgfHwgOSA9PT0gZS5ub2RlVHlwZSB8fCAhK2Uubm9kZVR5cGUgfTsgZnVuY3Rpb24gRygpIHsgdGhpcy5leHBhbmRvID0gdy5leHBhbmRvICsgRy51aWQrKyB9IEcudWlkID0gMSwgRy5wcm90b3R5cGUgPSB7IGNhY2hlOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGVbdGhpcy5leHBhbmRvXTsgcmV0dXJuIHQgfHwgKHQgPSB7fSwgWShlKSAmJiAoZS5ub2RlVHlwZSA/IGVbdGhpcy5leHBhbmRvXSA9IHQgOiBPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwgdGhpcy5leHBhbmRvLCB7IHZhbHVlOiB0LCBjb25maWd1cmFibGU6ICEwIH0pKSksIHQgfSwgc2V0OiBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciwgaSA9IHRoaXMuY2FjaGUoZSk7IGlmICgic3RyaW5nIiA9PSB0eXBlb2YgdCkgaVtRKHQpXSA9IG47IGVsc2UgZm9yIChyIGluIHQpIGlbUShyKV0gPSB0W3JdOyByZXR1cm4gaSB9LCBnZXQ6IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiB2b2lkIDAgPT09IHQgPyB0aGlzLmNhY2hlKGUpIDogZVt0aGlzLmV4cGFuZG9dICYmIGVbdGhpcy5leHBhbmRvXVtRKHQpXSB9LCBhY2Nlc3M6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiB2b2lkIDAgPT09IHQgfHwgdCAmJiAic3RyaW5nIiA9PSB0eXBlb2YgdCAmJiB2b2lkIDAgPT09IG4gPyB0aGlzLmdldChlLCB0KSA6ICh0aGlzLnNldChlLCB0LCBuKSwgdm9pZCAwICE9PSBuID8gbiA6IHQpIH0sIHJlbW92ZTogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIgPSBlW3RoaXMuZXhwYW5kb107IGlmICh2b2lkIDAgIT09IHIpIHsgaWYgKHZvaWQgMCAhPT0gdCkgeyBuID0gKHQgPSBBcnJheS5pc0FycmF5KHQpID8gdC5tYXAoUSkgOiAodCA9IFEodCkpIGluIHIgPyBbdF0gOiB0Lm1hdGNoKEkpIHx8IFtdKS5sZW5ndGg7IHdoaWxlIChuLS0pIGRlbGV0ZSByW3Rbbl1dIH0gKHZvaWQgMCA9PT0gdCB8fCB3LmlzRW1wdHlPYmplY3QocikpICYmIChlLm5vZGVUeXBlID8gZVt0aGlzLmV4cGFuZG9dID0gdm9pZCAwIDogZGVsZXRlIGVbdGhpcy5leHBhbmRvXSkgfSB9LCBoYXNEYXRhOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGVbdGhpcy5leHBhbmRvXTsgcmV0dXJuIHZvaWQgMCAhPT0gdCAmJiAhdy5pc0VtcHR5T2JqZWN0KHQpIH0gfTsgdmFyIEsgPSBuZXcgRywgSiA9IG5ldyBHLCBaID0gL14oPzpce1tcd1xXXSpcfXxcW1tcd1xXXSpcXSkkLywgZWUgPSAvW0EtWl0vZzsgZnVuY3Rpb24gdGUoZSkgeyByZXR1cm4gInRydWUiID09PSBlIHx8ICJmYWxzZSIgIT09IGUgJiYgKCJudWxsIiA9PT0gZSA/IG51bGwgOiBlID09PSArZSArICIiID8gK2UgOiBaLnRlc3QoZSkgPyBKU09OLnBhcnNlKGUpIDogZSkgfSBmdW5jdGlvbiBuZShlLCB0LCBuKSB7IHZhciByOyBpZiAodm9pZCAwID09PSBuICYmIDEgPT09IGUubm9kZVR5cGUpIGlmIChyID0gImRhdGEtIiArIHQucmVwbGFjZShlZSwgIi0kJiIpLnRvTG93ZXJDYXNlKCksICJzdHJpbmciID09IHR5cGVvZiAobiA9IGUuZ2V0QXR0cmlidXRlKHIpKSkgeyB0cnkgeyBuID0gdGUobikgfSBjYXRjaCAoZSkgeyB9IEouc2V0KGUsIHQsIG4pIH0gZWxzZSBuID0gdm9pZCAwOyByZXR1cm4gbiB9IHcuZXh0ZW5kKHsgaGFzRGF0YTogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEouaGFzRGF0YShlKSB8fCBLLmhhc0RhdGEoZSkgfSwgZGF0YTogZnVuY3Rpb24gKGUsIHQsIG4pIHsgcmV0dXJuIEouYWNjZXNzKGUsIHQsIG4pIH0sIHJlbW92ZURhdGE6IGZ1bmN0aW9uIChlLCB0KSB7IEoucmVtb3ZlKGUsIHQpIH0sIF9kYXRhOiBmdW5jdGlvbiAoZSwgdCwgbikgeyByZXR1cm4gSy5hY2Nlc3MoZSwgdCwgbikgfSwgX3JlbW92ZURhdGE6IGZ1bmN0aW9uIChlLCB0KSB7IEsucmVtb3ZlKGUsIHQpIH0gfSksIHcuZm4uZXh0ZW5kKHsgZGF0YTogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIsIGksIG8gPSB0aGlzWzBdLCBhID0gbyAmJiBvLmF0dHJpYnV0ZXM7IGlmICh2b2lkIDAgPT09IGUpIHsgaWYgKHRoaXMubGVuZ3RoICYmIChpID0gSi5nZXQobyksIDEgPT09IG8ubm9kZVR5cGUgJiYgIUsuZ2V0KG8sICJoYXNEYXRhQXR0cnMiKSkpIHsgbiA9IGEubGVuZ3RoOyB3aGlsZSAobi0tKSBhW25dICYmIDAgPT09IChyID0gYVtuXS5uYW1lKS5pbmRleE9mKCJkYXRhLSIpICYmIChyID0gUShyLnNsaWNlKDUpKSwgbmUobywgciwgaVtyXSkpOyBLLnNldChvLCAiaGFzRGF0YUF0dHJzIiwgITApIH0gcmV0dXJuIGkgfSByZXR1cm4gIm9iamVjdCIgPT0gdHlwZW9mIGUgPyB0aGlzLmVhY2goZnVuY3Rpb24gKCkgeyBKLnNldCh0aGlzLCBlKSB9KSA6IF8odGhpcywgZnVuY3Rpb24gKHQpIHsgdmFyIG47IGlmIChvICYmIHZvaWQgMCA9PT0gdCkgeyBpZiAodm9pZCAwICE9PSAobiA9IEouZ2V0KG8sIGUpKSkgcmV0dXJuIG47IGlmICh2b2lkIDAgIT09IChuID0gbmUobywgZSkpKSByZXR1cm4gbiB9IGVsc2UgdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgSi5zZXQodGhpcywgZSwgdCkgfSkgfSwgbnVsbCwgdCwgYXJndW1lbnRzLmxlbmd0aCA+IDEsIG51bGwsICEwKSB9LCByZW1vdmVEYXRhOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgSi5yZW1vdmUodGhpcywgZSkgfSkgfSB9KSwgdy5leHRlbmQoeyBxdWV1ZTogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHI7IGlmIChlKSByZXR1cm4gdCA9ICh0IHx8ICJmeCIpICsgInF1ZXVlIiwgciA9IEsuZ2V0KGUsIHQpLCBuICYmICghciB8fCBBcnJheS5pc0FycmF5KG4pID8gciA9IEsuYWNjZXNzKGUsIHQsIHcubWFrZUFycmF5KG4pKSA6IHIucHVzaChuKSksIHIgfHwgW10gfSwgZGVxdWV1ZTogZnVuY3Rpb24gKGUsIHQpIHsgdCA9IHQgfHwgImZ4IjsgdmFyIG4gPSB3LnF1ZXVlKGUsIHQpLCByID0gbi5sZW5ndGgsIGkgPSBuLnNoaWZ0KCksIG8gPSB3Ll9xdWV1ZUhvb2tzKGUsIHQpLCBhID0gZnVuY3Rpb24gKCkgeyB3LmRlcXVldWUoZSwgdCkgfTsgImlucHJvZ3Jlc3MiID09PSBpICYmIChpID0gbi5zaGlmdCgpLCByLS0pLCBpICYmICgiZngiID09PSB0ICYmIG4udW5zaGlmdCgiaW5wcm9ncmVzcyIpLCBkZWxldGUgby5zdG9wLCBpLmNhbGwoZSwgYSwgbykpLCAhciAmJiBvICYmIG8uZW1wdHkuZmlyZSgpIH0sIF9xdWV1ZUhvb2tzOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IHQgKyAicXVldWVIb29rcyI7IHJldHVybiBLLmdldChlLCBuKSB8fCBLLmFjY2VzcyhlLCBuLCB7IGVtcHR5OiB3LkNhbGxiYWNrcygib25jZSBtZW1vcnkiKS5hZGQoZnVuY3Rpb24gKCkgeyBLLnJlbW92ZShlLCBbdCArICJxdWV1ZSIsIG5dKSB9KSB9KSB9IH0pLCB3LmZuLmV4dGVuZCh7IHF1ZXVlOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IDI7IHJldHVybiAic3RyaW5nIiAhPSB0eXBlb2YgZSAmJiAodCA9IGUsIGUgPSAiZngiLCBuLS0pLCBhcmd1bWVudHMubGVuZ3RoIDwgbiA/IHcucXVldWUodGhpc1swXSwgZSkgOiB2b2lkIDAgPT09IHQgPyB0aGlzIDogdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgdmFyIG4gPSB3LnF1ZXVlKHRoaXMsIGUsIHQpOyB3Ll9xdWV1ZUhvb2tzKHRoaXMsIGUpLCAiZngiID09PSBlICYmICJpbnByb2dyZXNzIiAhPT0gblswXSAmJiB3LmRlcXVldWUodGhpcywgZSkgfSkgfSwgZGVxdWV1ZTogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7IHcuZGVxdWV1ZSh0aGlzLCBlKSB9KSB9LCBjbGVhclF1ZXVlOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5xdWV1ZShlIHx8ICJmeCIsIFtdKSB9LCBwcm9taXNlOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiwgciA9IDEsIGkgPSB3LkRlZmVycmVkKCksIG8gPSB0aGlzLCBhID0gdGhpcy5sZW5ndGgsIHUgPSBmdW5jdGlvbiAoKSB7IC0tciB8fCBpLnJlc29sdmVXaXRoKG8sIFtvXSkgfTsgInN0cmluZyIgIT0gdHlwZW9mIGUgJiYgKHQgPSBlLCBlID0gdm9pZCAwKSwgZSA9IGUgfHwgImZ4Ijsgd2hpbGUgKGEtLSkgKG4gPSBLLmdldChvW2FdLCBlICsgInF1ZXVlSG9va3MiKSkgJiYgbi5lbXB0eSAmJiAocisrICwgbi5lbXB0eS5hZGQodSkpOyByZXR1cm4gdSgpLCBpLnByb21pc2UodCkgfSB9KTsgdmFyIHJlID0gL1srLV0/KD86XGQqXC58KVxkKyg/OltlRV1bKy1dP1xkK3wpLy5zb3VyY2UsIGllID0gbmV3IFJlZ0V4cCgiXig/OihbKy1dKT18KSgiICsgcmUgKyAiKShbYS16JV0qKSQiLCAiaSIpLCBvZSA9IFsiVG9wIiwgIlJpZ2h0IiwgIkJvdHRvbSIsICJMZWZ0Il0sIGFlID0gZnVuY3Rpb24gKGUsIHQpIHsgcmV0dXJuICJub25lIiA9PT0gKGUgPSB0IHx8IGUpLnN0eWxlLmRpc3BsYXkgfHwgIiIgPT09IGUuc3R5bGUuZGlzcGxheSAmJiB3LmNvbnRhaW5zKGUub3duZXJEb2N1bWVudCwgZSkgJiYgIm5vbmUiID09PSB3LmNzcyhlLCAiZGlzcGxheSIpIH0sIHVlID0gZnVuY3Rpb24gKGUsIHQsIG4sIHIpIHsgdmFyIGksIG8sIGEgPSB7fTsgZm9yIChvIGluIHQpIGFbb10gPSBlLnN0eWxlW29dLCBlLnN0eWxlW29dID0gdFtvXTsgaSA9IG4uYXBwbHkoZSwgciB8fCBbXSk7IGZvciAobyBpbiB0KSBlLnN0eWxlW29dID0gYVtvXTsgcmV0dXJuIGkgfTsgZnVuY3Rpb24gc2UoZSwgdCwgbiwgcikgeyB2YXIgaSwgbywgYSA9IDIwLCB1ID0gciA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHIuY3VyKCkgfSA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHcuY3NzKGUsIHQsICIiKSB9LCBzID0gdSgpLCBsID0gbiAmJiBuWzNdIHx8ICh3LmNzc051bWJlclt0XSA/ICIiIDogInB4IiksIGMgPSAody5jc3NOdW1iZXJbdF0gfHwgInB4IiAhPT0gbCAmJiArcykgJiYgaWUuZXhlYyh3LmNzcyhlLCB0KSk7IGlmIChjICYmIGNbM10gIT09IGwpIHsgcyAvPSAyLCBsID0gbCB8fCBjWzNdLCBjID0gK3MgfHwgMTsgd2hpbGUgKGEtLSkgdy5zdHlsZShlLCB0LCBjICsgbCksICgxIC0gbykgKiAoMSAtIChvID0gdSgpIC8gcyB8fCAuNSkpIDw9IDAgJiYgKGEgPSAwKSwgYyAvPSBvOyBjICo9IDIsIHcuc3R5bGUoZSwgdCwgYyArIGwpLCBuID0gbiB8fCBbXSB9IHJldHVybiBuICYmIChjID0gK2MgfHwgK3MgfHwgMCwgaSA9IG5bMV0gPyBjICsgKG5bMV0gKyAxKSAqIG5bMl0gOiArblsyXSwgciAmJiAoci51bml0ID0gbCwgci5zdGFydCA9IGMsIHIuZW5kID0gaSkpLCBpIH0gdmFyIGxlID0ge307IGZ1bmN0aW9uIGNlKGUpIHsgdmFyIHQsIG4gPSBlLm93bmVyRG9jdW1lbnQsIHIgPSBlLm5vZGVOYW1lLCBpID0gbGVbcl07IHJldHVybiBpIHx8ICh0ID0gbi5ib2R5LmFwcGVuZENoaWxkKG4uY3JlYXRlRWxlbWVudChyKSksIGkgPSB3LmNzcyh0LCAiZGlzcGxheSIpLCB0LnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodCksICJub25lIiA9PT0gaSAmJiAoaSA9ICJibG9jayIpLCBsZVtyXSA9IGksIGkpIH0gZnVuY3Rpb24gZmUoZSwgdCkgeyBmb3IgKHZhciBuLCByLCBpID0gW10sIG8gPSAwLCBhID0gZS5sZW5ndGg7IG8gPCBhOyBvKyspKHIgPSBlW29dKS5zdHlsZSAmJiAobiA9IHIuc3R5bGUuZGlzcGxheSwgdCA/ICgibm9uZSIgPT09IG4gJiYgKGlbb10gPSBLLmdldChyLCAiZGlzcGxheSIpIHx8IG51bGwsIGlbb10gfHwgKHIuc3R5bGUuZGlzcGxheSA9ICIiKSksICIiID09PSByLnN0eWxlLmRpc3BsYXkgJiYgYWUocikgJiYgKGlbb10gPSBjZShyKSkpIDogIm5vbmUiICE9PSBuICYmIChpW29dID0gIm5vbmUiLCBLLnNldChyLCAiZGlzcGxheSIsIG4pKSk7IGZvciAobyA9IDA7IG8gPCBhOyBvKyspbnVsbCAhPSBpW29dICYmIChlW29dLnN0eWxlLmRpc3BsYXkgPSBpW29dKTsgcmV0dXJuIGUgfSB3LmZuLmV4dGVuZCh7IHNob3c6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGZlKHRoaXMsICEwKSB9LCBoaWRlOiBmdW5jdGlvbiAoKSB7IHJldHVybiBmZSh0aGlzKSB9LCB0b2dnbGU6IGZ1bmN0aW9uIChlKSB7IHJldHVybiAiYm9vbGVhbiIgPT0gdHlwZW9mIGUgPyBlID8gdGhpcy5zaG93KCkgOiB0aGlzLmhpZGUoKSA6IHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7IGFlKHRoaXMpID8gdyh0aGlzKS5zaG93KCkgOiB3KHRoaXMpLmhpZGUoKSB9KSB9IH0pOyB2YXIgZGUgPSAvXig/OmNoZWNrYm94fHJhZGlvKSQvaSwgcGUgPSAvPChbYS16XVteXC9cMD5ceDIwXHRcclxuXGZdKykvaSwgaGUgPSAvXiR8Xm1vZHVsZSR8XC8oPzpqYXZhfGVjbWEpc2NyaXB0L2ksIGdlID0geyBvcHRpb246IFsxLCAiPHNlbGVjdCBtdWx0aXBsZT0nbXVsdGlwbGUnPiIsICI8L3NlbGVjdD4iXSwgdGhlYWQ6IFsxLCAiPHRhYmxlPiIsICI8L3RhYmxlPiJdLCBjb2w6IFsyLCAiPHRhYmxlPjxjb2xncm91cD4iLCAiPC9jb2xncm91cD48L3RhYmxlPiJdLCB0cjogWzIsICI8dGFibGU+PHRib2R5PiIsICI8L3Rib2R5PjwvdGFibGU+Il0sIHRkOiBbMywgIjx0YWJsZT48dGJvZHk+PHRyPiIsICI8L3RyPjwvdGJvZHk+PC90YWJsZT4iXSwgX2RlZmF1bHQ6IFswLCAiIiwgIiJdIH07IGdlLm9wdGdyb3VwID0gZ2Uub3B0aW9uLCBnZS50Ym9keSA9IGdlLnRmb290ID0gZ2UuY29sZ3JvdXAgPSBnZS5jYXB0aW9uID0gZ2UudGhlYWQsIGdlLnRoID0gZ2UudGQ7IGZ1bmN0aW9uIHZlKGUsIHQpIHsgdmFyIG47IHJldHVybiBuID0gInVuZGVmaW5lZCIgIT0gdHlwZW9mIGUuZ2V0RWxlbWVudHNCeVRhZ05hbWUgPyBlLmdldEVsZW1lbnRzQnlUYWdOYW1lKHQgfHwgIioiKSA6ICJ1bmRlZmluZWQiICE9IHR5cGVvZiBlLnF1ZXJ5U2VsZWN0b3JBbGwgPyBlLnF1ZXJ5U2VsZWN0b3JBbGwodCB8fCAiKiIpIDogW10sIHZvaWQgMCA9PT0gdCB8fCB0ICYmIEQoZSwgdCkgPyB3Lm1lcmdlKFtlXSwgbikgOiBuIH0gZnVuY3Rpb24geWUoZSwgdCkgeyBmb3IgKHZhciBuID0gMCwgciA9IGUubGVuZ3RoOyBuIDwgcjsgbisrKUsuc2V0KGVbbl0sICJnbG9iYWxFdmFsIiwgIXQgfHwgSy5nZXQodFtuXSwgImdsb2JhbEV2YWwiKSkgfSB2YXIgbWUgPSAvPHwmIz9cdys7LzsgZnVuY3Rpb24gYmUoZSwgdCwgbiwgciwgaSkgeyBmb3IgKHZhciBvLCBhLCB1LCBzLCBsLCBjLCBmID0gdC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCksIGQgPSBbXSwgcCA9IDAsIGggPSBlLmxlbmd0aDsgcCA8IGg7IHArKylpZiAoKG8gPSBlW3BdKSB8fCAwID09PSBvKSBpZiAoIm9iamVjdCIgPT09IGIobykpIHcubWVyZ2UoZCwgby5ub2RlVHlwZSA/IFtvXSA6IG8pOyBlbHNlIGlmIChtZS50ZXN0KG8pKSB7IGEgPSBhIHx8IGYuYXBwZW5kQ2hpbGQodC5jcmVhdGVFbGVtZW50KCJkaXYiKSksIHUgPSAocGUuZXhlYyhvKSB8fCBbIiIsICIiXSlbMV0udG9Mb3dlckNhc2UoKSwgcyA9IGdlW3VdIHx8IGdlLl9kZWZhdWx0LCBhLmlubmVySFRNTCA9IHNbMV0gKyB3Lmh0bWxQcmVmaWx0ZXIobykgKyBzWzJdLCBjID0gc1swXTsgd2hpbGUgKGMtLSkgYSA9IGEubGFzdENoaWxkOyB3Lm1lcmdlKGQsIGEuY2hpbGROb2RlcyksIChhID0gZi5maXJzdENoaWxkKS50ZXh0Q29udGVudCA9ICIiIH0gZWxzZSBkLnB1c2godC5jcmVhdGVUZXh0Tm9kZShvKSk7IGYudGV4dENvbnRlbnQgPSAiIiwgcCA9IDA7IHdoaWxlIChvID0gZFtwKytdKSBpZiAociAmJiB3LmluQXJyYXkobywgcikgPiAtMSkgaSAmJiBpLnB1c2gobyk7IGVsc2UgaWYgKGwgPSB3LmNvbnRhaW5zKG8ub3duZXJEb2N1bWVudCwgbyksIGEgPSB2ZShmLmFwcGVuZENoaWxkKG8pLCAic2NyaXB0IiksIGwgJiYgeWUoYSksIG4pIHsgYyA9IDA7IHdoaWxlIChvID0gYVtjKytdKSBoZS50ZXN0KG8udHlwZSB8fCAiIikgJiYgbi5wdXNoKG8pIH0gcmV0dXJuIGYgfSAhZnVuY3Rpb24gKCkgeyB2YXIgZSA9IHIuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLmFwcGVuZENoaWxkKHIuY3JlYXRlRWxlbWVudCgiZGl2IikpLCB0ID0gci5jcmVhdGVFbGVtZW50KCJpbnB1dCIpOyB0LnNldEF0dHJpYnV0ZSgidHlwZSIsICJyYWRpbyIpLCB0LnNldEF0dHJpYnV0ZSgiY2hlY2tlZCIsICJjaGVja2VkIiksIHQuc2V0QXR0cmlidXRlKCJuYW1lIiwgInQiKSwgZS5hcHBlbmRDaGlsZCh0KSwgaC5jaGVja0Nsb25lID0gZS5jbG9uZU5vZGUoITApLmNsb25lTm9kZSghMCkubGFzdENoaWxkLmNoZWNrZWQsIGUuaW5uZXJIVE1MID0gIjx0ZXh0YXJlYT54PC90ZXh0YXJlYT4iLCBoLm5vQ2xvbmVDaGVja2VkID0gISFlLmNsb25lTm9kZSghMCkubGFzdENoaWxkLmRlZmF1bHRWYWx1ZSB9KCk7IHZhciB4ZSA9IHIuZG9jdW1lbnRFbGVtZW50LCB3ZSA9IC9ea2V5LywgQ2UgPSAvXig/Om1vdXNlfHBvaW50ZXJ8Y29udGV4dG1lbnV8ZHJhZ3xkcm9wKXxjbGljay8sIFRlID0gL14oW14uXSopKD86XC4oLispfCkvOyBmdW5jdGlvbiBFZSgpIHsgcmV0dXJuICEwIH0gZnVuY3Rpb24gTmUoKSB7IHJldHVybiAhMSB9IGZ1bmN0aW9uIGtlKCkgeyB0cnkgeyByZXR1cm4gci5hY3RpdmVFbGVtZW50IH0gY2F0Y2ggKGUpIHsgfSB9IGZ1bmN0aW9uIEFlKGUsIHQsIG4sIHIsIGksIG8pIHsgdmFyIGEsIHU7IGlmICgib2JqZWN0IiA9PSB0eXBlb2YgdCkgeyAic3RyaW5nIiAhPSB0eXBlb2YgbiAmJiAociA9IHIgfHwgbiwgbiA9IHZvaWQgMCk7IGZvciAodSBpbiB0KSBBZShlLCB1LCBuLCByLCB0W3VdLCBvKTsgcmV0dXJuIGUgfSBpZiAobnVsbCA9PSByICYmIG51bGwgPT0gaSA/IChpID0gbiwgciA9IG4gPSB2b2lkIDApIDogbnVsbCA9PSBpICYmICgic3RyaW5nIiA9PSB0eXBlb2YgbiA/IChpID0gciwgciA9IHZvaWQgMCkgOiAoaSA9IHIsIHIgPSBuLCBuID0gdm9pZCAwKSksICExID09PSBpKSBpID0gTmU7IGVsc2UgaWYgKCFpKSByZXR1cm4gZTsgcmV0dXJuIDEgPT09IG8gJiYgKGEgPSBpLCAoaSA9IGZ1bmN0aW9uIChlKSB7IHJldHVybiB3KCkub2ZmKGUpLCBhLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykgfSkuZ3VpZCA9IGEuZ3VpZCB8fCAoYS5ndWlkID0gdy5ndWlkKyspKSwgZS5lYWNoKGZ1bmN0aW9uICgpIHsgdy5ldmVudC5hZGQodGhpcywgdCwgaSwgciwgbikgfSkgfSB3LmV2ZW50ID0geyBnbG9iYWw6IHt9LCBhZGQ6IGZ1bmN0aW9uIChlLCB0LCBuLCByLCBpKSB7IHZhciBvLCBhLCB1LCBzLCBsLCBjLCBmLCBkLCBwLCBoLCBnLCB2ID0gSy5nZXQoZSk7IGlmICh2KSB7IG4uaGFuZGxlciAmJiAobiA9IChvID0gbikuaGFuZGxlciwgaSA9IG8uc2VsZWN0b3IpLCBpICYmIHcuZmluZC5tYXRjaGVzU2VsZWN0b3IoeGUsIGkpLCBuLmd1aWQgfHwgKG4uZ3VpZCA9IHcuZ3VpZCsrKSwgKHMgPSB2LmV2ZW50cykgfHwgKHMgPSB2LmV2ZW50cyA9IHt9KSwgKGEgPSB2LmhhbmRsZSkgfHwgKGEgPSB2LmhhbmRsZSA9IGZ1bmN0aW9uICh0KSB7IHJldHVybiAidW5kZWZpbmVkIiAhPSB0eXBlb2YgdyAmJiB3LmV2ZW50LnRyaWdnZXJlZCAhPT0gdC50eXBlID8gdy5ldmVudC5kaXNwYXRjaC5hcHBseShlLCBhcmd1bWVudHMpIDogdm9pZCAwIH0pLCBsID0gKHQgPSAodCB8fCAiIikubWF0Y2goSSkgfHwgWyIiXSkubGVuZ3RoOyB3aGlsZSAobC0tKSBwID0gZyA9ICh1ID0gVGUuZXhlYyh0W2xdKSB8fCBbXSlbMV0sIGggPSAodVsyXSB8fCAiIikuc3BsaXQoIi4iKS5zb3J0KCksIHAgJiYgKGYgPSB3LmV2ZW50LnNwZWNpYWxbcF0gfHwge30sIHAgPSAoaSA/IGYuZGVsZWdhdGVUeXBlIDogZi5iaW5kVHlwZSkgfHwgcCwgZiA9IHcuZXZlbnQuc3BlY2lhbFtwXSB8fCB7fSwgYyA9IHcuZXh0ZW5kKHsgdHlwZTogcCwgb3JpZ1R5cGU6IGcsIGRhdGE6IHIsIGhhbmRsZXI6IG4sIGd1aWQ6IG4uZ3VpZCwgc2VsZWN0b3I6IGksIG5lZWRzQ29udGV4dDogaSAmJiB3LmV4cHIubWF0Y2gubmVlZHNDb250ZXh0LnRlc3QoaSksIG5hbWVzcGFjZTogaC5qb2luKCIuIikgfSwgbyksIChkID0gc1twXSkgfHwgKChkID0gc1twXSA9IFtdKS5kZWxlZ2F0ZUNvdW50ID0gMCwgZi5zZXR1cCAmJiAhMSAhPT0gZi5zZXR1cC5jYWxsKGUsIHIsIGgsIGEpIHx8IGUuYWRkRXZlbnRMaXN0ZW5lciAmJiBlLmFkZEV2ZW50TGlzdGVuZXIocCwgYSkpLCBmLmFkZCAmJiAoZi5hZGQuY2FsbChlLCBjKSwgYy5oYW5kbGVyLmd1aWQgfHwgKGMuaGFuZGxlci5ndWlkID0gbi5ndWlkKSksIGkgPyBkLnNwbGljZShkLmRlbGVnYXRlQ291bnQrKywgMCwgYykgOiBkLnB1c2goYyksIHcuZXZlbnQuZ2xvYmFsW3BdID0gITApIH0gfSwgcmVtb3ZlOiBmdW5jdGlvbiAoZSwgdCwgbiwgciwgaSkgeyB2YXIgbywgYSwgdSwgcywgbCwgYywgZiwgZCwgcCwgaCwgZywgdiA9IEsuaGFzRGF0YShlKSAmJiBLLmdldChlKTsgaWYgKHYgJiYgKHMgPSB2LmV2ZW50cykpIHsgbCA9ICh0ID0gKHQgfHwgIiIpLm1hdGNoKEkpIHx8IFsiIl0pLmxlbmd0aDsgd2hpbGUgKGwtLSkgaWYgKHUgPSBUZS5leGVjKHRbbF0pIHx8IFtdLCBwID0gZyA9IHVbMV0sIGggPSAodVsyXSB8fCAiIikuc3BsaXQoIi4iKS5zb3J0KCksIHApIHsgZiA9IHcuZXZlbnQuc3BlY2lhbFtwXSB8fCB7fSwgZCA9IHNbcCA9IChyID8gZi5kZWxlZ2F0ZVR5cGUgOiBmLmJpbmRUeXBlKSB8fCBwXSB8fCBbXSwgdSA9IHVbMl0gJiYgbmV3IFJlZ0V4cCgiKF58XFwuKSIgKyBoLmpvaW4oIlxcLig/Oi4qXFwufCkiKSArICIoXFwufCQpIiksIGEgPSBvID0gZC5sZW5ndGg7IHdoaWxlIChvLS0pIGMgPSBkW29dLCAhaSAmJiBnICE9PSBjLm9yaWdUeXBlIHx8IG4gJiYgbi5ndWlkICE9PSBjLmd1aWQgfHwgdSAmJiAhdS50ZXN0KGMubmFtZXNwYWNlKSB8fCByICYmIHIgIT09IGMuc2VsZWN0b3IgJiYgKCIqKiIgIT09IHIgfHwgIWMuc2VsZWN0b3IpIHx8IChkLnNwbGljZShvLCAxKSwgYy5zZWxlY3RvciAmJiBkLmRlbGVnYXRlQ291bnQtLSAsIGYucmVtb3ZlICYmIGYucmVtb3ZlLmNhbGwoZSwgYykpOyBhICYmICFkLmxlbmd0aCAmJiAoZi50ZWFyZG93biAmJiAhMSAhPT0gZi50ZWFyZG93bi5jYWxsKGUsIGgsIHYuaGFuZGxlKSB8fCB3LnJlbW92ZUV2ZW50KGUsIHAsIHYuaGFuZGxlKSwgZGVsZXRlIHNbcF0pIH0gZWxzZSBmb3IgKHAgaW4gcykgdy5ldmVudC5yZW1vdmUoZSwgcCArIHRbbF0sIG4sIHIsICEwKTsgdy5pc0VtcHR5T2JqZWN0KHMpICYmIEsucmVtb3ZlKGUsICJoYW5kbGUgZXZlbnRzIikgfSB9LCBkaXNwYXRjaDogZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSB3LmV2ZW50LmZpeChlKSwgbiwgciwgaSwgbywgYSwgdSwgcyA9IG5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoKSwgbCA9IChLLmdldCh0aGlzLCAiZXZlbnRzIikgfHwge30pW3QudHlwZV0gfHwgW10sIGMgPSB3LmV2ZW50LnNwZWNpYWxbdC50eXBlXSB8fCB7fTsgZm9yIChzWzBdID0gdCwgbiA9IDE7IG4gPCBhcmd1bWVudHMubGVuZ3RoOyBuKyspc1tuXSA9IGFyZ3VtZW50c1tuXTsgaWYgKHQuZGVsZWdhdGVUYXJnZXQgPSB0aGlzLCAhYy5wcmVEaXNwYXRjaCB8fCAhMSAhPT0gYy5wcmVEaXNwYXRjaC5jYWxsKHRoaXMsIHQpKSB7IHUgPSB3LmV2ZW50LmhhbmRsZXJzLmNhbGwodGhpcywgdCwgbCksIG4gPSAwOyB3aGlsZSAoKG8gPSB1W24rK10pICYmICF0LmlzUHJvcGFnYXRpb25TdG9wcGVkKCkpIHsgdC5jdXJyZW50VGFyZ2V0ID0gby5lbGVtLCByID0gMDsgd2hpbGUgKChhID0gby5oYW5kbGVyc1tyKytdKSAmJiAhdC5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCgpKSB0LnJuYW1lc3BhY2UgJiYgIXQucm5hbWVzcGFjZS50ZXN0KGEubmFtZXNwYWNlKSB8fCAodC5oYW5kbGVPYmogPSBhLCB0LmRhdGEgPSBhLmRhdGEsIHZvaWQgMCAhPT0gKGkgPSAoKHcuZXZlbnQuc3BlY2lhbFthLm9yaWdUeXBlXSB8fCB7fSkuaGFuZGxlIHx8IGEuaGFuZGxlcikuYXBwbHkoby5lbGVtLCBzKSkgJiYgITEgPT09ICh0LnJlc3VsdCA9IGkpICYmICh0LnByZXZlbnREZWZhdWx0KCksIHQuc3RvcFByb3BhZ2F0aW9uKCkpKSB9IHJldHVybiBjLnBvc3REaXNwYXRjaCAmJiBjLnBvc3REaXNwYXRjaC5jYWxsKHRoaXMsIHQpLCB0LnJlc3VsdCB9IH0sIGhhbmRsZXJzOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiwgciwgaSwgbywgYSwgdSA9IFtdLCBzID0gdC5kZWxlZ2F0ZUNvdW50LCBsID0gZS50YXJnZXQ7IGlmIChzICYmIGwubm9kZVR5cGUgJiYgISgiY2xpY2siID09PSBlLnR5cGUgJiYgZS5idXR0b24gPj0gMSkpIGZvciAoOyBsICE9PSB0aGlzOyBsID0gbC5wYXJlbnROb2RlIHx8IHRoaXMpaWYgKDEgPT09IGwubm9kZVR5cGUgJiYgKCJjbGljayIgIT09IGUudHlwZSB8fCAhMCAhPT0gbC5kaXNhYmxlZCkpIHsgZm9yIChvID0gW10sIGEgPSB7fSwgbiA9IDA7IG4gPCBzOyBuKyspdm9pZCAwID09PSBhW2kgPSAociA9IHRbbl0pLnNlbGVjdG9yICsgIiAiXSAmJiAoYVtpXSA9IHIubmVlZHNDb250ZXh0ID8gdyhpLCB0aGlzKS5pbmRleChsKSA+IC0xIDogdy5maW5kKGksIHRoaXMsIG51bGwsIFtsXSkubGVuZ3RoKSwgYVtpXSAmJiBvLnB1c2gocik7IG8ubGVuZ3RoICYmIHUucHVzaCh7IGVsZW06IGwsIGhhbmRsZXJzOiBvIH0pIH0gcmV0dXJuIGwgPSB0aGlzLCBzIDwgdC5sZW5ndGggJiYgdS5wdXNoKHsgZWxlbTogbCwgaGFuZGxlcnM6IHQuc2xpY2UocykgfSksIHUgfSwgYWRkUHJvcDogZnVuY3Rpb24gKGUsIHQpIHsgT2JqZWN0LmRlZmluZVByb3BlcnR5KHcuRXZlbnQucHJvdG90eXBlLCBlLCB7IGVudW1lcmFibGU6ICEwLCBjb25maWd1cmFibGU6ICEwLCBnZXQ6IGcodCkgPyBmdW5jdGlvbiAoKSB7IGlmICh0aGlzLm9yaWdpbmFsRXZlbnQpIHJldHVybiB0KHRoaXMub3JpZ2luYWxFdmVudCkgfSA6IGZ1bmN0aW9uICgpIHsgaWYgKHRoaXMub3JpZ2luYWxFdmVudCkgcmV0dXJuIHRoaXMub3JpZ2luYWxFdmVudFtlXSB9LCBzZXQ6IGZ1bmN0aW9uICh0KSB7IE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBlLCB7IGVudW1lcmFibGU6ICEwLCBjb25maWd1cmFibGU6ICEwLCB3cml0YWJsZTogITAsIHZhbHVlOiB0IH0pIH0gfSkgfSwgZml4OiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gZVt3LmV4cGFuZG9dID8gZSA6IG5ldyB3LkV2ZW50KGUpIH0sIHNwZWNpYWw6IHsgbG9hZDogeyBub0J1YmJsZTogITAgfSwgZm9jdXM6IHsgdHJpZ2dlcjogZnVuY3Rpb24gKCkgeyBpZiAodGhpcyAhPT0ga2UoKSAmJiB0aGlzLmZvY3VzKSByZXR1cm4gdGhpcy5mb2N1cygpLCAhMSB9LCBkZWxlZ2F0ZVR5cGU6ICJmb2N1c2luIiB9LCBibHVyOiB7IHRyaWdnZXI6IGZ1bmN0aW9uICgpIHsgaWYgKHRoaXMgPT09IGtlKCkgJiYgdGhpcy5ibHVyKSByZXR1cm4gdGhpcy5ibHVyKCksICExIH0sIGRlbGVnYXRlVHlwZTogImZvY3Vzb3V0IiB9LCBjbGljazogeyB0cmlnZ2VyOiBmdW5jdGlvbiAoKSB7IGlmICgiY2hlY2tib3giID09PSB0aGlzLnR5cGUgJiYgdGhpcy5jbGljayAmJiBEKHRoaXMsICJpbnB1dCIpKSByZXR1cm4gdGhpcy5jbGljaygpLCAhMSB9LCBfZGVmYXVsdDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIEQoZS50YXJnZXQsICJhIikgfSB9LCBiZWZvcmV1bmxvYWQ6IHsgcG9zdERpc3BhdGNoOiBmdW5jdGlvbiAoZSkgeyB2b2lkIDAgIT09IGUucmVzdWx0ICYmIGUub3JpZ2luYWxFdmVudCAmJiAoZS5vcmlnaW5hbEV2ZW50LnJldHVyblZhbHVlID0gZS5yZXN1bHQpIH0gfSB9IH0sIHcucmVtb3ZlRXZlbnQgPSBmdW5jdGlvbiAoZSwgdCwgbikgeyBlLnJlbW92ZUV2ZW50TGlzdGVuZXIgJiYgZS5yZW1vdmVFdmVudExpc3RlbmVyKHQsIG4pIH0sIHcuRXZlbnQgPSBmdW5jdGlvbiAoZSwgdCkgeyBpZiAoISh0aGlzIGluc3RhbmNlb2Ygdy5FdmVudCkpIHJldHVybiBuZXcgdy5FdmVudChlLCB0KTsgZSAmJiBlLnR5cGUgPyAodGhpcy5vcmlnaW5hbEV2ZW50ID0gZSwgdGhpcy50eXBlID0gZS50eXBlLCB0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IGUuZGVmYXVsdFByZXZlbnRlZCB8fCB2b2lkIDAgPT09IGUuZGVmYXVsdFByZXZlbnRlZCAmJiAhMSA9PT0gZS5yZXR1cm5WYWx1ZSA/IEVlIDogTmUsIHRoaXMudGFyZ2V0ID0gZS50YXJnZXQgJiYgMyA9PT0gZS50YXJnZXQubm9kZVR5cGUgPyBlLnRhcmdldC5wYXJlbnROb2RlIDogZS50YXJnZXQsIHRoaXMuY3VycmVudFRhcmdldCA9IGUuY3VycmVudFRhcmdldCwgdGhpcy5yZWxhdGVkVGFyZ2V0ID0gZS5yZWxhdGVkVGFyZ2V0KSA6IHRoaXMudHlwZSA9IGUsIHQgJiYgdy5leHRlbmQodGhpcywgdCksIHRoaXMudGltZVN0YW1wID0gZSAmJiBlLnRpbWVTdGFtcCB8fCBEYXRlLm5vdygpLCB0aGlzW3cuZXhwYW5kb10gPSAhMCB9LCB3LkV2ZW50LnByb3RvdHlwZSA9IHsgY29uc3RydWN0b3I6IHcuRXZlbnQsIGlzRGVmYXVsdFByZXZlbnRlZDogTmUsIGlzUHJvcGFnYXRpb25TdG9wcGVkOiBOZSwgaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQ6IE5lLCBpc1NpbXVsYXRlZDogITEsIHByZXZlbnREZWZhdWx0OiBmdW5jdGlvbiAoKSB7IHZhciBlID0gdGhpcy5vcmlnaW5hbEV2ZW50OyB0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IEVlLCBlICYmICF0aGlzLmlzU2ltdWxhdGVkICYmIGUucHJldmVudERlZmF1bHQoKSB9LCBzdG9wUHJvcGFnYXRpb246IGZ1bmN0aW9uICgpIHsgdmFyIGUgPSB0aGlzLm9yaWdpbmFsRXZlbnQ7IHRoaXMuaXNQcm9wYWdhdGlvblN0b3BwZWQgPSBFZSwgZSAmJiAhdGhpcy5pc1NpbXVsYXRlZCAmJiBlLnN0b3BQcm9wYWdhdGlvbigpIH0sIHN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbjogZnVuY3Rpb24gKCkgeyB2YXIgZSA9IHRoaXMub3JpZ2luYWxFdmVudDsgdGhpcy5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCA9IEVlLCBlICYmICF0aGlzLmlzU2ltdWxhdGVkICYmIGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCksIHRoaXMuc3RvcFByb3BhZ2F0aW9uKCkgfSB9LCB3LmVhY2goeyBhbHRLZXk6ICEwLCBidWJibGVzOiAhMCwgY2FuY2VsYWJsZTogITAsIGNoYW5nZWRUb3VjaGVzOiAhMCwgY3RybEtleTogITAsIGRldGFpbDogITAsIGV2ZW50UGhhc2U6ICEwLCBtZXRhS2V5OiAhMCwgcGFnZVg6ICEwLCBwYWdlWTogITAsIHNoaWZ0S2V5OiAhMCwgdmlldzogITAsICJjaGFyIjogITAsIGNoYXJDb2RlOiAhMCwga2V5OiAhMCwga2V5Q29kZTogITAsIGJ1dHRvbjogITAsIGJ1dHRvbnM6ICEwLCBjbGllbnRYOiAhMCwgY2xpZW50WTogITAsIG9mZnNldFg6ICEwLCBvZmZzZXRZOiAhMCwgcG9pbnRlcklkOiAhMCwgcG9pbnRlclR5cGU6ICEwLCBzY3JlZW5YOiAhMCwgc2NyZWVuWTogITAsIHRhcmdldFRvdWNoZXM6ICEwLCB0b0VsZW1lbnQ6ICEwLCB0b3VjaGVzOiAhMCwgd2hpY2g6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZS5idXR0b247IHJldHVybiBudWxsID09IGUud2hpY2ggJiYgd2UudGVzdChlLnR5cGUpID8gbnVsbCAhPSBlLmNoYXJDb2RlID8gZS5jaGFyQ29kZSA6IGUua2V5Q29kZSA6ICFlLndoaWNoICYmIHZvaWQgMCAhPT0gdCAmJiBDZS50ZXN0KGUudHlwZSkgPyAxICYgdCA/IDEgOiAyICYgdCA/IDMgOiA0ICYgdCA/IDIgOiAwIDogZS53aGljaCB9IH0sIHcuZXZlbnQuYWRkUHJvcCksIHcuZWFjaCh7IG1vdXNlZW50ZXI6ICJtb3VzZW92ZXIiLCBtb3VzZWxlYXZlOiAibW91c2VvdXQiLCBwb2ludGVyZW50ZXI6ICJwb2ludGVyb3ZlciIsIHBvaW50ZXJsZWF2ZTogInBvaW50ZXJvdXQiIH0sIGZ1bmN0aW9uIChlLCB0KSB7IHcuZXZlbnQuc3BlY2lhbFtlXSA9IHsgZGVsZWdhdGVUeXBlOiB0LCBiaW5kVHlwZTogdCwgaGFuZGxlOiBmdW5jdGlvbiAoZSkgeyB2YXIgbiwgciA9IHRoaXMsIGkgPSBlLnJlbGF0ZWRUYXJnZXQsIG8gPSBlLmhhbmRsZU9iajsgcmV0dXJuIGkgJiYgKGkgPT09IHIgfHwgdy5jb250YWlucyhyLCBpKSkgfHwgKGUudHlwZSA9IG8ub3JpZ1R5cGUsIG4gPSBvLmhhbmRsZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKSwgZS50eXBlID0gdCksIG4gfSB9IH0pLCB3LmZuLmV4dGVuZCh7IG9uOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyByZXR1cm4gQWUodGhpcywgZSwgdCwgbiwgcikgfSwgb25lOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyByZXR1cm4gQWUodGhpcywgZSwgdCwgbiwgciwgMSkgfSwgb2ZmOiBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciwgaTsgaWYgKGUgJiYgZS5wcmV2ZW50RGVmYXVsdCAmJiBlLmhhbmRsZU9iaikgcmV0dXJuIHIgPSBlLmhhbmRsZU9iaiwgdyhlLmRlbGVnYXRlVGFyZ2V0KS5vZmYoci5uYW1lc3BhY2UgPyByLm9yaWdUeXBlICsgIi4iICsgci5uYW1lc3BhY2UgOiByLm9yaWdUeXBlLCByLnNlbGVjdG9yLCByLmhhbmRsZXIpLCB0aGlzOyBpZiAoIm9iamVjdCIgPT0gdHlwZW9mIGUpIHsgZm9yIChpIGluIGUpIHRoaXMub2ZmKGksIHQsIGVbaV0pOyByZXR1cm4gdGhpcyB9IHJldHVybiAhMSAhPT0gdCAmJiAiZnVuY3Rpb24iICE9IHR5cGVvZiB0IHx8IChuID0gdCwgdCA9IHZvaWQgMCksICExID09PSBuICYmIChuID0gTmUpLCB0aGlzLmVhY2goZnVuY3Rpb24gKCkgeyB3LmV2ZW50LnJlbW92ZSh0aGlzLCBlLCBuLCB0KSB9KSB9IH0pOyB2YXIgRGUgPSAvPCg/IWFyZWF8YnJ8Y29sfGVtYmVkfGhyfGltZ3xpbnB1dHxsaW5rfG1ldGF8cGFyYW0pKChbYS16XVteXC9cMD5ceDIwXHRcclxuXGZdKilbXj5dKilcLz4vZ2ksIFNlID0gLzxzY3JpcHR8PHN0eWxlfDxsaW5rL2ksIExlID0gL2NoZWNrZWRccyooPzpbXj1dfD1ccyouY2hlY2tlZC4pL2ksIGplID0gL15ccyo8ISg/OlxbQ0RBVEFcW3wtLSl8KD86XF1cXXwtLSk+XHMqJC9nOyBmdW5jdGlvbiBxZShlLCB0KSB7IHJldHVybiBEKGUsICJ0YWJsZSIpICYmIEQoMTEgIT09IHQubm9kZVR5cGUgPyB0IDogdC5maXJzdENoaWxkLCAidHIiKSA/IHcoZSkuY2hpbGRyZW4oInRib2R5IilbMF0gfHwgZSA6IGUgfSBmdW5jdGlvbiBPZShlKSB7IHJldHVybiBlLnR5cGUgPSAobnVsbCAhPT0gZS5nZXRBdHRyaWJ1dGUoInR5cGUiKSkgKyAiLyIgKyBlLnR5cGUsIGUgfSBmdW5jdGlvbiBQZShlKSB7IHJldHVybiAidHJ1ZS8iID09PSAoZS50eXBlIHx8ICIiKS5zbGljZSgwLCA1KSA/IGUudHlwZSA9IGUudHlwZS5zbGljZSg1KSA6IGUucmVtb3ZlQXR0cmlidXRlKCJ0eXBlIiksIGUgfSBmdW5jdGlvbiBIZShlLCB0KSB7IHZhciBuLCByLCBpLCBvLCBhLCB1LCBzLCBsOyBpZiAoMSA9PT0gdC5ub2RlVHlwZSkgeyBpZiAoSy5oYXNEYXRhKGUpICYmIChvID0gSy5hY2Nlc3MoZSksIGEgPSBLLnNldCh0LCBvKSwgbCA9IG8uZXZlbnRzKSkgeyBkZWxldGUgYS5oYW5kbGUsIGEuZXZlbnRzID0ge307IGZvciAoaSBpbiBsKSBmb3IgKG4gPSAwLCByID0gbFtpXS5sZW5ndGg7IG4gPCByOyBuKyspdy5ldmVudC5hZGQodCwgaSwgbFtpXVtuXSkgfSBKLmhhc0RhdGEoZSkgJiYgKHUgPSBKLmFjY2VzcyhlKSwgcyA9IHcuZXh0ZW5kKHt9LCB1KSwgSi5zZXQodCwgcykpIH0gfSBmdW5jdGlvbiBJZShlLCB0KSB7IHZhciBuID0gdC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpOyAiaW5wdXQiID09PSBuICYmIGRlLnRlc3QoZS50eXBlKSA/IHQuY2hlY2tlZCA9IGUuY2hlY2tlZCA6ICJpbnB1dCIgIT09IG4gJiYgInRleHRhcmVhIiAhPT0gbiB8fCAodC5kZWZhdWx0VmFsdWUgPSBlLmRlZmF1bHRWYWx1ZSkgfSBmdW5jdGlvbiBSZShlLCB0LCBuLCByKSB7IHQgPSBhLmFwcGx5KFtdLCB0KTsgdmFyIGksIG8sIHUsIHMsIGwsIGMsIGYgPSAwLCBkID0gZS5sZW5ndGgsIHAgPSBkIC0gMSwgdiA9IHRbMF0sIHkgPSBnKHYpOyBpZiAoeSB8fCBkID4gMSAmJiAic3RyaW5nIiA9PSB0eXBlb2YgdiAmJiAhaC5jaGVja0Nsb25lICYmIExlLnRlc3QodikpIHJldHVybiBlLmVhY2goZnVuY3Rpb24gKGkpIHsgdmFyIG8gPSBlLmVxKGkpOyB5ICYmICh0WzBdID0gdi5jYWxsKHRoaXMsIGksIG8uaHRtbCgpKSksIFJlKG8sIHQsIG4sIHIpIH0pOyBpZiAoZCAmJiAoaSA9IGJlKHQsIGVbMF0ub3duZXJEb2N1bWVudCwgITEsIGUsIHIpLCBvID0gaS5maXJzdENoaWxkLCAxID09PSBpLmNoaWxkTm9kZXMubGVuZ3RoICYmIChpID0gbyksIG8gfHwgcikpIHsgZm9yIChzID0gKHUgPSB3Lm1hcCh2ZShpLCAic2NyaXB0IiksIE9lKSkubGVuZ3RoOyBmIDwgZDsgZisrKWwgPSBpLCBmICE9PSBwICYmIChsID0gdy5jbG9uZShsLCAhMCwgITApLCBzICYmIHcubWVyZ2UodSwgdmUobCwgInNjcmlwdCIpKSksIG4uY2FsbChlW2ZdLCBsLCBmKTsgaWYgKHMpIGZvciAoYyA9IHVbdS5sZW5ndGggLSAxXS5vd25lckRvY3VtZW50LCB3Lm1hcCh1LCBQZSksIGYgPSAwOyBmIDwgczsgZisrKWwgPSB1W2ZdLCBoZS50ZXN0KGwudHlwZSB8fCAiIikgJiYgIUsuYWNjZXNzKGwsICJnbG9iYWxFdmFsIikgJiYgdy5jb250YWlucyhjLCBsKSAmJiAobC5zcmMgJiYgIm1vZHVsZSIgIT09IChsLnR5cGUgfHwgIiIpLnRvTG93ZXJDYXNlKCkgPyB3Ll9ldmFsVXJsICYmIHcuX2V2YWxVcmwobC5zcmMpIDogbShsLnRleHRDb250ZW50LnJlcGxhY2UoamUsICIiKSwgYywgbCkpIH0gcmV0dXJuIGUgfSBmdW5jdGlvbiBCZShlLCB0LCBuKSB7IGZvciAodmFyIHIsIGkgPSB0ID8gdy5maWx0ZXIodCwgZSkgOiBlLCBvID0gMDsgbnVsbCAhPSAociA9IGlbb10pOyBvKyspbiB8fCAxICE9PSByLm5vZGVUeXBlIHx8IHcuY2xlYW5EYXRhKHZlKHIpKSwgci5wYXJlbnROb2RlICYmIChuICYmIHcuY29udGFpbnMoci5vd25lckRvY3VtZW50LCByKSAmJiB5ZSh2ZShyLCAic2NyaXB0IikpLCByLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQocikpOyByZXR1cm4gZSB9IHcuZXh0ZW5kKHsgaHRtbFByZWZpbHRlcjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGUucmVwbGFjZShEZSwgIjwkMT48LyQyPiIpIH0sIGNsb25lOiBmdW5jdGlvbiAoZSwgdCwgbikgeyB2YXIgciwgaSwgbywgYSwgdSA9IGUuY2xvbmVOb2RlKCEwKSwgcyA9IHcuY29udGFpbnMoZS5vd25lckRvY3VtZW50LCBlKTsgaWYgKCEoaC5ub0Nsb25lQ2hlY2tlZCB8fCAxICE9PSBlLm5vZGVUeXBlICYmIDExICE9PSBlLm5vZGVUeXBlIHx8IHcuaXNYTUxEb2MoZSkpKSBmb3IgKGEgPSB2ZSh1KSwgciA9IDAsIGkgPSAobyA9IHZlKGUpKS5sZW5ndGg7IHIgPCBpOyByKyspSWUob1tyXSwgYVtyXSk7IGlmICh0KSBpZiAobikgZm9yIChvID0gbyB8fCB2ZShlKSwgYSA9IGEgfHwgdmUodSksIHIgPSAwLCBpID0gby5sZW5ndGg7IHIgPCBpOyByKyspSGUob1tyXSwgYVtyXSk7IGVsc2UgSGUoZSwgdSk7IHJldHVybiAoYSA9IHZlKHUsICJzY3JpcHQiKSkubGVuZ3RoID4gMCAmJiB5ZShhLCAhcyAmJiB2ZShlLCAic2NyaXB0IikpLCB1IH0sIGNsZWFuRGF0YTogZnVuY3Rpb24gKGUpIHsgZm9yICh2YXIgdCwgbiwgciwgaSA9IHcuZXZlbnQuc3BlY2lhbCwgbyA9IDA7IHZvaWQgMCAhPT0gKG4gPSBlW29dKTsgbysrKWlmIChZKG4pKSB7IGlmICh0ID0gbltLLmV4cGFuZG9dKSB7IGlmICh0LmV2ZW50cykgZm9yIChyIGluIHQuZXZlbnRzKSBpW3JdID8gdy5ldmVudC5yZW1vdmUobiwgcikgOiB3LnJlbW92ZUV2ZW50KG4sIHIsIHQuaGFuZGxlKTsgbltLLmV4cGFuZG9dID0gdm9pZCAwIH0gbltKLmV4cGFuZG9dICYmIChuW0ouZXhwYW5kb10gPSB2b2lkIDApIH0gfSB9KSwgdy5mbi5leHRlbmQoeyBkZXRhY2g6IGZ1bmN0aW9uIChlKSB7IHJldHVybiBCZSh0aGlzLCBlLCAhMCkgfSwgcmVtb3ZlOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gQmUodGhpcywgZSkgfSwgdGV4dDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIF8odGhpcywgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHZvaWQgMCA9PT0gZSA/IHcudGV4dCh0aGlzKSA6IHRoaXMuZW1wdHkoKS5lYWNoKGZ1bmN0aW9uICgpIHsgMSAhPT0gdGhpcy5ub2RlVHlwZSAmJiAxMSAhPT0gdGhpcy5ub2RlVHlwZSAmJiA5ICE9PSB0aGlzLm5vZGVUeXBlIHx8ICh0aGlzLnRleHRDb250ZW50ID0gZSkgfSkgfSwgbnVsbCwgZSwgYXJndW1lbnRzLmxlbmd0aCkgfSwgYXBwZW5kOiBmdW5jdGlvbiAoKSB7IHJldHVybiBSZSh0aGlzLCBhcmd1bWVudHMsIGZ1bmN0aW9uIChlKSB7IDEgIT09IHRoaXMubm9kZVR5cGUgJiYgMTEgIT09IHRoaXMubm9kZVR5cGUgJiYgOSAhPT0gdGhpcy5ub2RlVHlwZSB8fCBxZSh0aGlzLCBlKS5hcHBlbmRDaGlsZChlKSB9KSB9LCBwcmVwZW5kOiBmdW5jdGlvbiAoKSB7IHJldHVybiBSZSh0aGlzLCBhcmd1bWVudHMsIGZ1bmN0aW9uIChlKSB7IGlmICgxID09PSB0aGlzLm5vZGVUeXBlIHx8IDExID09PSB0aGlzLm5vZGVUeXBlIHx8IDkgPT09IHRoaXMubm9kZVR5cGUpIHsgdmFyIHQgPSBxZSh0aGlzLCBlKTsgdC5pbnNlcnRCZWZvcmUoZSwgdC5maXJzdENoaWxkKSB9IH0pIH0sIGJlZm9yZTogZnVuY3Rpb24gKCkgeyByZXR1cm4gUmUodGhpcywgYXJndW1lbnRzLCBmdW5jdGlvbiAoZSkgeyB0aGlzLnBhcmVudE5vZGUgJiYgdGhpcy5wYXJlbnROb2RlLmluc2VydEJlZm9yZShlLCB0aGlzKSB9KSB9LCBhZnRlcjogZnVuY3Rpb24gKCkgeyByZXR1cm4gUmUodGhpcywgYXJndW1lbnRzLCBmdW5jdGlvbiAoZSkgeyB0aGlzLnBhcmVudE5vZGUgJiYgdGhpcy5wYXJlbnROb2RlLmluc2VydEJlZm9yZShlLCB0aGlzLm5leHRTaWJsaW5nKSB9KSB9LCBlbXB0eTogZnVuY3Rpb24gKCkgeyBmb3IgKHZhciBlLCB0ID0gMDsgbnVsbCAhPSAoZSA9IHRoaXNbdF0pOyB0KyspMSA9PT0gZS5ub2RlVHlwZSAmJiAody5jbGVhbkRhdGEodmUoZSwgITEpKSwgZS50ZXh0Q29udGVudCA9ICIiKTsgcmV0dXJuIHRoaXMgfSwgY2xvbmU6IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiBlID0gbnVsbCAhPSBlICYmIGUsIHQgPSBudWxsID09IHQgPyBlIDogdCwgdGhpcy5tYXAoZnVuY3Rpb24gKCkgeyByZXR1cm4gdy5jbG9uZSh0aGlzLCBlLCB0KSB9KSB9LCBodG1sOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gXyh0aGlzLCBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IHRoaXNbMF0gfHwge30sIG4gPSAwLCByID0gdGhpcy5sZW5ndGg7IGlmICh2b2lkIDAgPT09IGUgJiYgMSA9PT0gdC5ub2RlVHlwZSkgcmV0dXJuIHQuaW5uZXJIVE1MOyBpZiAoInN0cmluZyIgPT0gdHlwZW9mIGUgJiYgIVNlLnRlc3QoZSkgJiYgIWdlWyhwZS5leGVjKGUpIHx8IFsiIiwgIiJdKVsxXS50b0xvd2VyQ2FzZSgpXSkgeyBlID0gdy5odG1sUHJlZmlsdGVyKGUpOyB0cnkgeyBmb3IgKDsgbiA8IHI7IG4rKykxID09PSAodCA9IHRoaXNbbl0gfHwge30pLm5vZGVUeXBlICYmICh3LmNsZWFuRGF0YSh2ZSh0LCAhMSkpLCB0LmlubmVySFRNTCA9IGUpOyB0ID0gMCB9IGNhdGNoIChlKSB7IH0gfSB0ICYmIHRoaXMuZW1wdHkoKS5hcHBlbmQoZSkgfSwgbnVsbCwgZSwgYXJndW1lbnRzLmxlbmd0aCkgfSwgcmVwbGFjZVdpdGg6IGZ1bmN0aW9uICgpIHsgdmFyIGUgPSBbXTsgcmV0dXJuIFJlKHRoaXMsIGFyZ3VtZW50cywgZnVuY3Rpb24gKHQpIHsgdmFyIG4gPSB0aGlzLnBhcmVudE5vZGU7IHcuaW5BcnJheSh0aGlzLCBlKSA8IDAgJiYgKHcuY2xlYW5EYXRhKHZlKHRoaXMpKSwgbiAmJiBuLnJlcGxhY2VDaGlsZCh0LCB0aGlzKSkgfSwgZSkgfSB9KSwgdy5lYWNoKHsgYXBwZW5kVG86ICJhcHBlbmQiLCBwcmVwZW5kVG86ICJwcmVwZW5kIiwgaW5zZXJ0QmVmb3JlOiAiYmVmb3JlIiwgaW5zZXJ0QWZ0ZXI6ICJhZnRlciIsIHJlcGxhY2VBbGw6ICJyZXBsYWNlV2l0aCIgfSwgZnVuY3Rpb24gKGUsIHQpIHsgdy5mbltlXSA9IGZ1bmN0aW9uIChlKSB7IGZvciAodmFyIG4sIHIgPSBbXSwgaSA9IHcoZSksIG8gPSBpLmxlbmd0aCAtIDEsIGEgPSAwOyBhIDw9IG87IGErKyluID0gYSA9PT0gbyA/IHRoaXMgOiB0aGlzLmNsb25lKCEwKSwgdyhpW2FdKVt0XShuKSwgdS5hcHBseShyLCBuLmdldCgpKTsgcmV0dXJuIHRoaXMucHVzaFN0YWNrKHIpIH0gfSk7IHZhciBNZSA9IG5ldyBSZWdFeHAoIl4oIiArIHJlICsgIikoPyFweClbYS16JV0rJCIsICJpIiksIFdlID0gZnVuY3Rpb24gKHQpIHsgdmFyIG4gPSB0Lm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXc7IHJldHVybiBuICYmIG4ub3BlbmVyIHx8IChuID0gZSksIG4uZ2V0Q29tcHV0ZWRTdHlsZSh0KSB9LCAkZSA9IG5ldyBSZWdFeHAob2Uuam9pbigifCIpLCAiaSIpOyAhZnVuY3Rpb24gKCkgeyBmdW5jdGlvbiB0KCkgeyBpZiAoYykgeyBsLnN0eWxlLmNzc1RleHQgPSAicG9zaXRpb246YWJzb2x1dGU7bGVmdDotMTExMTFweDt3aWR0aDo2MHB4O21hcmdpbi10b3A6MXB4O3BhZGRpbmc6MDtib3JkZXI6MCIsIGMuc3R5bGUuY3NzVGV4dCA9ICJwb3NpdGlvbjpyZWxhdGl2ZTtkaXNwbGF5OmJsb2NrO2JveC1zaXppbmc6Ym9yZGVyLWJveDtvdmVyZmxvdzpzY3JvbGw7bWFyZ2luOmF1dG87Ym9yZGVyOjFweDtwYWRkaW5nOjFweDt3aWR0aDo2MCU7dG9wOjElIiwgeGUuYXBwZW5kQ2hpbGQobCkuYXBwZW5kQ2hpbGQoYyk7IHZhciB0ID0gZS5nZXRDb21wdXRlZFN0eWxlKGMpOyBpID0gIjElIiAhPT0gdC50b3AsIHMgPSAxMiA9PT0gbih0Lm1hcmdpbkxlZnQpLCBjLnN0eWxlLnJpZ2h0ID0gIjYwJSIsIHUgPSAzNiA9PT0gbih0LnJpZ2h0KSwgbyA9IDM2ID09PSBuKHQud2lkdGgpLCBjLnN0eWxlLnBvc2l0aW9uID0gImFic29sdXRlIiwgYSA9IDM2ID09PSBjLm9mZnNldFdpZHRoIHx8ICJhYnNvbHV0ZSIsIHhlLnJlbW92ZUNoaWxkKGwpLCBjID0gbnVsbCB9IH0gZnVuY3Rpb24gbihlKSB7IHJldHVybiBNYXRoLnJvdW5kKHBhcnNlRmxvYXQoZSkpIH0gdmFyIGksIG8sIGEsIHUsIHMsIGwgPSByLmNyZWF0ZUVsZW1lbnQoImRpdiIpLCBjID0gci5jcmVhdGVFbGVtZW50KCJkaXYiKTsgYy5zdHlsZSAmJiAoYy5zdHlsZS5iYWNrZ3JvdW5kQ2xpcCA9ICJjb250ZW50LWJveCIsIGMuY2xvbmVOb2RlKCEwKS5zdHlsZS5iYWNrZ3JvdW5kQ2xpcCA9ICIiLCBoLmNsZWFyQ2xvbmVTdHlsZSA9ICJjb250ZW50LWJveCIgPT09IGMuc3R5bGUuYmFja2dyb3VuZENsaXAsIHcuZXh0ZW5kKGgsIHsgYm94U2l6aW5nUmVsaWFibGU6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHQoKSwgbyB9LCBwaXhlbEJveFN0eWxlczogZnVuY3Rpb24gKCkgeyByZXR1cm4gdCgpLCB1IH0sIHBpeGVsUG9zaXRpb246IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHQoKSwgaSB9LCByZWxpYWJsZU1hcmdpbkxlZnQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHQoKSwgcyB9LCBzY3JvbGxib3hTaXplOiBmdW5jdGlvbiAoKSB7IHJldHVybiB0KCksIGEgfSB9KSkgfSgpOyBmdW5jdGlvbiBGZShlLCB0LCBuKSB7IHZhciByLCBpLCBvLCBhLCB1ID0gZS5zdHlsZTsgcmV0dXJuIChuID0gbiB8fCBXZShlKSkgJiYgKCIiICE9PSAoYSA9IG4uZ2V0UHJvcGVydHlWYWx1ZSh0KSB8fCBuW3RdKSB8fCB3LmNvbnRhaW5zKGUub3duZXJEb2N1bWVudCwgZSkgfHwgKGEgPSB3LnN0eWxlKGUsIHQpKSwgIWgucGl4ZWxCb3hTdHlsZXMoKSAmJiBNZS50ZXN0KGEpICYmICRlLnRlc3QodCkgJiYgKHIgPSB1LndpZHRoLCBpID0gdS5taW5XaWR0aCwgbyA9IHUubWF4V2lkdGgsIHUubWluV2lkdGggPSB1Lm1heFdpZHRoID0gdS53aWR0aCA9IGEsIGEgPSBuLndpZHRoLCB1LndpZHRoID0gciwgdS5taW5XaWR0aCA9IGksIHUubWF4V2lkdGggPSBvKSksIHZvaWQgMCAhPT0gYSA/IGEgKyAiIiA6IGEgfSBmdW5jdGlvbiB6ZShlLCB0KSB7IHJldHVybiB7IGdldDogZnVuY3Rpb24gKCkgeyBpZiAoIWUoKSkgcmV0dXJuICh0aGlzLmdldCA9IHQpLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IGRlbGV0ZSB0aGlzLmdldCB9IH0gfSB2YXIgX2UgPSAvXihub25lfHRhYmxlKD8hLWNbZWFdKS4rKS8sIFVlID0gL14tLS8sIFZlID0geyBwb3NpdGlvbjogImFic29sdXRlIiwgdmlzaWJpbGl0eTogImhpZGRlbiIsIGRpc3BsYXk6ICJibG9jayIgfSwgWGUgPSB7IGxldHRlclNwYWNpbmc6ICIwIiwgZm9udFdlaWdodDogIjQwMCIgfSwgUWUgPSBbIldlYmtpdCIsICJNb3oiLCAibXMiXSwgWWUgPSByLmNyZWF0ZUVsZW1lbnQoImRpdiIpLnN0eWxlOyBmdW5jdGlvbiBHZShlKSB7IGlmIChlIGluIFllKSByZXR1cm4gZTsgdmFyIHQgPSBlWzBdLnRvVXBwZXJDYXNlKCkgKyBlLnNsaWNlKDEpLCBuID0gUWUubGVuZ3RoOyB3aGlsZSAobi0tKSBpZiAoKGUgPSBRZVtuXSArIHQpIGluIFllKSByZXR1cm4gZSB9IGZ1bmN0aW9uIEtlKGUpIHsgdmFyIHQgPSB3LmNzc1Byb3BzW2VdOyByZXR1cm4gdCB8fCAodCA9IHcuY3NzUHJvcHNbZV0gPSBHZShlKSB8fCBlKSwgdCB9IGZ1bmN0aW9uIEplKGUsIHQsIG4pIHsgdmFyIHIgPSBpZS5leGVjKHQpOyByZXR1cm4gciA/IE1hdGgubWF4KDAsIHJbMl0gLSAobiB8fCAwKSkgKyAoclszXSB8fCAicHgiKSA6IHQgfSBmdW5jdGlvbiBaZShlLCB0LCBuLCByLCBpLCBvKSB7IHZhciBhID0gIndpZHRoIiA9PT0gdCA/IDEgOiAwLCB1ID0gMCwgcyA9IDA7IGlmIChuID09PSAociA/ICJib3JkZXIiIDogImNvbnRlbnQiKSkgcmV0dXJuIDA7IGZvciAoOyBhIDwgNDsgYSArPSAyKSJtYXJnaW4iID09PSBuICYmIChzICs9IHcuY3NzKGUsIG4gKyBvZVthXSwgITAsIGkpKSwgciA/ICgiY29udGVudCIgPT09IG4gJiYgKHMgLT0gdy5jc3MoZSwgInBhZGRpbmciICsgb2VbYV0sICEwLCBpKSksICJtYXJnaW4iICE9PSBuICYmIChzIC09IHcuY3NzKGUsICJib3JkZXIiICsgb2VbYV0gKyAiV2lkdGgiLCAhMCwgaSkpKSA6IChzICs9IHcuY3NzKGUsICJwYWRkaW5nIiArIG9lW2FdLCAhMCwgaSksICJwYWRkaW5nIiAhPT0gbiA/IHMgKz0gdy5jc3MoZSwgImJvcmRlciIgKyBvZVthXSArICJXaWR0aCIsICEwLCBpKSA6IHUgKz0gdy5jc3MoZSwgImJvcmRlciIgKyBvZVthXSArICJXaWR0aCIsICEwLCBpKSk7IHJldHVybiAhciAmJiBvID49IDAgJiYgKHMgKz0gTWF0aC5tYXgoMCwgTWF0aC5jZWlsKGVbIm9mZnNldCIgKyB0WzBdLnRvVXBwZXJDYXNlKCkgKyB0LnNsaWNlKDEpXSAtIG8gLSBzIC0gdSAtIC41KSkpLCBzIH0gZnVuY3Rpb24gZXQoZSwgdCwgbikgeyB2YXIgciA9IFdlKGUpLCBpID0gRmUoZSwgdCwgciksIG8gPSAiYm9yZGVyLWJveCIgPT09IHcuY3NzKGUsICJib3hTaXppbmciLCAhMSwgciksIGEgPSBvOyBpZiAoTWUudGVzdChpKSkgeyBpZiAoIW4pIHJldHVybiBpOyBpID0gImF1dG8iIH0gcmV0dXJuIGEgPSBhICYmIChoLmJveFNpemluZ1JlbGlhYmxlKCkgfHwgaSA9PT0gZS5zdHlsZVt0XSksICgiYXV0byIgPT09IGkgfHwgIXBhcnNlRmxvYXQoaSkgJiYgImlubGluZSIgPT09IHcuY3NzKGUsICJkaXNwbGF5IiwgITEsIHIpKSAmJiAoaSA9IGVbIm9mZnNldCIgKyB0WzBdLnRvVXBwZXJDYXNlKCkgKyB0LnNsaWNlKDEpXSwgYSA9ICEwKSwgKGkgPSBwYXJzZUZsb2F0KGkpIHx8IDApICsgWmUoZSwgdCwgbiB8fCAobyA/ICJib3JkZXIiIDogImNvbnRlbnQiKSwgYSwgciwgaSkgKyAicHgiIH0gdy5leHRlbmQoeyBjc3NIb29rczogeyBvcGFjaXR5OiB7IGdldDogZnVuY3Rpb24gKGUsIHQpIHsgaWYgKHQpIHsgdmFyIG4gPSBGZShlLCAib3BhY2l0eSIpOyByZXR1cm4gIiIgPT09IG4gPyAiMSIgOiBuIH0gfSB9IH0sIGNzc051bWJlcjogeyBhbmltYXRpb25JdGVyYXRpb25Db3VudDogITAsIGNvbHVtbkNvdW50OiAhMCwgZmlsbE9wYWNpdHk6ICEwLCBmbGV4R3JvdzogITAsIGZsZXhTaHJpbms6ICEwLCBmb250V2VpZ2h0OiAhMCwgbGluZUhlaWdodDogITAsIG9wYWNpdHk6ICEwLCBvcmRlcjogITAsIG9ycGhhbnM6ICEwLCB3aWRvd3M6ICEwLCB6SW5kZXg6ICEwLCB6b29tOiAhMCB9LCBjc3NQcm9wczoge30sIHN0eWxlOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyBpZiAoZSAmJiAzICE9PSBlLm5vZGVUeXBlICYmIDggIT09IGUubm9kZVR5cGUgJiYgZS5zdHlsZSkgeyB2YXIgaSwgbywgYSwgdSA9IFEodCksIHMgPSBVZS50ZXN0KHQpLCBsID0gZS5zdHlsZTsgaWYgKHMgfHwgKHQgPSBLZSh1KSksIGEgPSB3LmNzc0hvb2tzW3RdIHx8IHcuY3NzSG9va3NbdV0sIHZvaWQgMCA9PT0gbikgcmV0dXJuIGEgJiYgImdldCIgaW4gYSAmJiB2b2lkIDAgIT09IChpID0gYS5nZXQoZSwgITEsIHIpKSA/IGkgOiBsW3RdOyAic3RyaW5nIiA9PSAobyA9IHR5cGVvZiBuKSAmJiAoaSA9IGllLmV4ZWMobikpICYmIGlbMV0gJiYgKG4gPSBzZShlLCB0LCBpKSwgbyA9ICJudW1iZXIiKSwgbnVsbCAhPSBuICYmIG4gPT09IG4gJiYgKCJudW1iZXIiID09PSBvICYmIChuICs9IGkgJiYgaVszXSB8fCAody5jc3NOdW1iZXJbdV0gPyAiIiA6ICJweCIpKSwgaC5jbGVhckNsb25lU3R5bGUgfHwgIiIgIT09IG4gfHwgMCAhPT0gdC5pbmRleE9mKCJiYWNrZ3JvdW5kIikgfHwgKGxbdF0gPSAiaW5oZXJpdCIpLCBhICYmICJzZXQiIGluIGEgJiYgdm9pZCAwID09PSAobiA9IGEuc2V0KGUsIG4sIHIpKSB8fCAocyA/IGwuc2V0UHJvcGVydHkodCwgbikgOiBsW3RdID0gbikpIH0gfSwgY3NzOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyB2YXIgaSwgbywgYSwgdSA9IFEodCk7IHJldHVybiBVZS50ZXN0KHQpIHx8ICh0ID0gS2UodSkpLCAoYSA9IHcuY3NzSG9va3NbdF0gfHwgdy5jc3NIb29rc1t1XSkgJiYgImdldCIgaW4gYSAmJiAoaSA9IGEuZ2V0KGUsICEwLCBuKSksIHZvaWQgMCA9PT0gaSAmJiAoaSA9IEZlKGUsIHQsIHIpKSwgIm5vcm1hbCIgPT09IGkgJiYgdCBpbiBYZSAmJiAoaSA9IFhlW3RdKSwgIiIgPT09IG4gfHwgbiA/IChvID0gcGFyc2VGbG9hdChpKSwgITAgPT09IG4gfHwgaXNGaW5pdGUobykgPyBvIHx8IDAgOiBpKSA6IGkgfSB9KSwgdy5lYWNoKFsiaGVpZ2h0IiwgIndpZHRoIl0sIGZ1bmN0aW9uIChlLCB0KSB7IHcuY3NzSG9va3NbdF0gPSB7IGdldDogZnVuY3Rpb24gKGUsIG4sIHIpIHsgaWYgKG4pIHJldHVybiAhX2UudGVzdCh3LmNzcyhlLCAiZGlzcGxheSIpKSB8fCBlLmdldENsaWVudFJlY3RzKCkubGVuZ3RoICYmIGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGggPyBldChlLCB0LCByKSA6IHVlKGUsIFZlLCBmdW5jdGlvbiAoKSB7IHJldHVybiBldChlLCB0LCByKSB9KSB9LCBzZXQ6IGZ1bmN0aW9uIChlLCBuLCByKSB7IHZhciBpLCBvID0gV2UoZSksIGEgPSAiYm9yZGVyLWJveCIgPT09IHcuY3NzKGUsICJib3hTaXppbmciLCAhMSwgbyksIHUgPSByICYmIFplKGUsIHQsIHIsIGEsIG8pOyByZXR1cm4gYSAmJiBoLnNjcm9sbGJveFNpemUoKSA9PT0gby5wb3NpdGlvbiAmJiAodSAtPSBNYXRoLmNlaWwoZVsib2Zmc2V0IiArIHRbMF0udG9VcHBlckNhc2UoKSArIHQuc2xpY2UoMSldIC0gcGFyc2VGbG9hdChvW3RdKSAtIFplKGUsIHQsICJib3JkZXIiLCAhMSwgbykgLSAuNSkpLCB1ICYmIChpID0gaWUuZXhlYyhuKSkgJiYgInB4IiAhPT0gKGlbM10gfHwgInB4IikgJiYgKGUuc3R5bGVbdF0gPSBuLCBuID0gdy5jc3MoZSwgdCkpLCBKZShlLCBuLCB1KSB9IH0gfSksIHcuY3NzSG9va3MubWFyZ2luTGVmdCA9IHplKGgucmVsaWFibGVNYXJnaW5MZWZ0LCBmdW5jdGlvbiAoZSwgdCkgeyBpZiAodCkgcmV0dXJuIChwYXJzZUZsb2F0KEZlKGUsICJtYXJnaW5MZWZ0IikpIHx8IGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkubGVmdCAtIHVlKGUsIHsgbWFyZ2luTGVmdDogMCB9LCBmdW5jdGlvbiAoKSB7IHJldHVybiBlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQgfSkpICsgInB4IiB9KSwgdy5lYWNoKHsgbWFyZ2luOiAiIiwgcGFkZGluZzogIiIsIGJvcmRlcjogIldpZHRoIiB9LCBmdW5jdGlvbiAoZSwgdCkgeyB3LmNzc0hvb2tzW2UgKyB0XSA9IHsgZXhwYW5kOiBmdW5jdGlvbiAobikgeyBmb3IgKHZhciByID0gMCwgaSA9IHt9LCBvID0gInN0cmluZyIgPT0gdHlwZW9mIG4gPyBuLnNwbGl0KCIgIikgOiBbbl07IHIgPCA0OyByKyspaVtlICsgb2Vbcl0gKyB0XSA9IG9bcl0gfHwgb1tyIC0gMl0gfHwgb1swXTsgcmV0dXJuIGkgfSB9LCAibWFyZ2luIiAhPT0gZSAmJiAody5jc3NIb29rc1tlICsgdF0uc2V0ID0gSmUpIH0pLCB3LmZuLmV4dGVuZCh7IGNzczogZnVuY3Rpb24gKGUsIHQpIHsgcmV0dXJuIF8odGhpcywgZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIsIGksIG8gPSB7fSwgYSA9IDA7IGlmIChBcnJheS5pc0FycmF5KHQpKSB7IGZvciAociA9IFdlKGUpLCBpID0gdC5sZW5ndGg7IGEgPCBpOyBhKyspb1t0W2FdXSA9IHcuY3NzKGUsIHRbYV0sICExLCByKTsgcmV0dXJuIG8gfSByZXR1cm4gdm9pZCAwICE9PSBuID8gdy5zdHlsZShlLCB0LCBuKSA6IHcuY3NzKGUsIHQpIH0sIGUsIHQsIGFyZ3VtZW50cy5sZW5ndGggPiAxKSB9IH0pLCB3LmZuLmRlbGF5ID0gZnVuY3Rpb24gKHQsIG4pIHsgcmV0dXJuIHQgPSB3LmZ4ID8gdy5meC5zcGVlZHNbdF0gfHwgdCA6IHQsIG4gPSBuIHx8ICJmeCIsIHRoaXMucXVldWUobiwgZnVuY3Rpb24gKG4sIHIpIHsgdmFyIGkgPSBlLnNldFRpbWVvdXQobiwgdCk7IHIuc3RvcCA9IGZ1bmN0aW9uICgpIHsgZS5jbGVhclRpbWVvdXQoaSkgfSB9KSB9LCBmdW5jdGlvbiAoKSB7IHZhciBlID0gci5jcmVhdGVFbGVtZW50KCJpbnB1dCIpLCB0ID0gci5jcmVhdGVFbGVtZW50KCJzZWxlY3QiKS5hcHBlbmRDaGlsZChyLmNyZWF0ZUVsZW1lbnQoIm9wdGlvbiIpKTsgZS50eXBlID0gImNoZWNrYm94IiwgaC5jaGVja09uID0gIiIgIT09IGUudmFsdWUsIGgub3B0U2VsZWN0ZWQgPSB0LnNlbGVjdGVkLCAoZSA9IHIuY3JlYXRlRWxlbWVudCgiaW5wdXQiKSkudmFsdWUgPSAidCIsIGUudHlwZSA9ICJyYWRpbyIsIGgucmFkaW9WYWx1ZSA9ICJ0IiA9PT0gZS52YWx1ZSB9KCk7IHZhciB0dCwgbnQgPSB3LmV4cHIuYXR0ckhhbmRsZTsgdy5mbi5leHRlbmQoeyBhdHRyOiBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gXyh0aGlzLCB3LmF0dHIsIGUsIHQsIGFyZ3VtZW50cy5sZW5ndGggPiAxKSB9LCByZW1vdmVBdHRyOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgdy5yZW1vdmVBdHRyKHRoaXMsIGUpIH0pIH0gfSksIHcuZXh0ZW5kKHsgYXR0cjogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIsIGksIG8gPSBlLm5vZGVUeXBlOyBpZiAoMyAhPT0gbyAmJiA4ICE9PSBvICYmIDIgIT09IG8pIHJldHVybiAidW5kZWZpbmVkIiA9PSB0eXBlb2YgZS5nZXRBdHRyaWJ1dGUgPyB3LnByb3AoZSwgdCwgbikgOiAoMSA9PT0gbyAmJiB3LmlzWE1MRG9jKGUpIHx8IChpID0gdy5hdHRySG9va3NbdC50b0xvd2VyQ2FzZSgpXSB8fCAody5leHByLm1hdGNoLmJvb2wudGVzdCh0KSA/IHR0IDogdm9pZCAwKSksIHZvaWQgMCAhPT0gbiA/IG51bGwgPT09IG4gPyB2b2lkIHcucmVtb3ZlQXR0cihlLCB0KSA6IGkgJiYgInNldCIgaW4gaSAmJiB2b2lkIDAgIT09IChyID0gaS5zZXQoZSwgbiwgdCkpID8gciA6IChlLnNldEF0dHJpYnV0ZSh0LCBuICsgIiIpLCBuKSA6IGkgJiYgImdldCIgaW4gaSAmJiBudWxsICE9PSAociA9IGkuZ2V0KGUsIHQpKSA/IHIgOiBudWxsID09IChyID0gdy5maW5kLmF0dHIoZSwgdCkpID8gdm9pZCAwIDogcikgfSwgYXR0ckhvb2tzOiB7IHR5cGU6IHsgc2V0OiBmdW5jdGlvbiAoZSwgdCkgeyBpZiAoIWgucmFkaW9WYWx1ZSAmJiAicmFkaW8iID09PSB0ICYmIEQoZSwgImlucHV0IikpIHsgdmFyIG4gPSBlLnZhbHVlOyByZXR1cm4gZS5zZXRBdHRyaWJ1dGUoInR5cGUiLCB0KSwgbiAmJiAoZS52YWx1ZSA9IG4pLCB0IH0gfSB9IH0sIHJlbW92ZUF0dHI6IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCByID0gMCwgaSA9IHQgJiYgdC5tYXRjaChJKTsgaWYgKGkgJiYgMSA9PT0gZS5ub2RlVHlwZSkgd2hpbGUgKG4gPSBpW3IrK10pIGUucmVtb3ZlQXR0cmlidXRlKG4pIH0gfSksIHR0ID0geyBzZXQ6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiAhMSA9PT0gdCA/IHcucmVtb3ZlQXR0cihlLCBuKSA6IGUuc2V0QXR0cmlidXRlKG4sIG4pLCBuIH0gfSwgdy5lYWNoKHcuZXhwci5tYXRjaC5ib29sLnNvdXJjZS5tYXRjaCgvXHcrL2cpLCBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IG50W3RdIHx8IHcuZmluZC5hdHRyOyBudFt0XSA9IGZ1bmN0aW9uIChlLCB0LCByKSB7IHZhciBpLCBvLCBhID0gdC50b0xvd2VyQ2FzZSgpOyByZXR1cm4gciB8fCAobyA9IG50W2FdLCBudFthXSA9IGksIGkgPSBudWxsICE9IG4oZSwgdCwgcikgPyBhIDogbnVsbCwgbnRbYV0gPSBvKSwgaSB9IH0pOyB2YXIgcnQgPSAvXig/OmlucHV0fHNlbGVjdHx0ZXh0YXJlYXxidXR0b24pJC9pLCBpdCA9IC9eKD86YXxhcmVhKSQvaTsgdy5mbi5leHRlbmQoeyBwcm9wOiBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gXyh0aGlzLCB3LnByb3AsIGUsIHQsIGFyZ3VtZW50cy5sZW5ndGggPiAxKSB9LCByZW1vdmVQcm9wOiBmdW5jdGlvbiAoZSkgeyByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgZGVsZXRlIHRoaXNbdy5wcm9wRml4W2VdIHx8IGVdIH0pIH0gfSksIHcuZXh0ZW5kKHsgcHJvcDogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIsIGksIG8gPSBlLm5vZGVUeXBlOyBpZiAoMyAhPT0gbyAmJiA4ICE9PSBvICYmIDIgIT09IG8pIHJldHVybiAxID09PSBvICYmIHcuaXNYTUxEb2MoZSkgfHwgKHQgPSB3LnByb3BGaXhbdF0gfHwgdCwgaSA9IHcucHJvcEhvb2tzW3RdKSwgdm9pZCAwICE9PSBuID8gaSAmJiAic2V0IiBpbiBpICYmIHZvaWQgMCAhPT0gKHIgPSBpLnNldChlLCBuLCB0KSkgPyByIDogZVt0XSA9IG4gOiBpICYmICJnZXQiIGluIGkgJiYgbnVsbCAhPT0gKHIgPSBpLmdldChlLCB0KSkgPyByIDogZVt0XSB9LCBwcm9wSG9va3M6IHsgdGFiSW5kZXg6IHsgZ2V0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IHcuZmluZC5hdHRyKGUsICJ0YWJpbmRleCIpOyByZXR1cm4gdCA/IHBhcnNlSW50KHQsIDEwKSA6IHJ0LnRlc3QoZS5ub2RlTmFtZSkgfHwgaXQudGVzdChlLm5vZGVOYW1lKSAmJiBlLmhyZWYgPyAwIDogLTEgfSB9IH0sIHByb3BGaXg6IHsgImZvciI6ICJodG1sRm9yIiwgImNsYXNzIjogImNsYXNzTmFtZSIgfSB9KSwgaC5vcHRTZWxlY3RlZCB8fCAody5wcm9wSG9va3Muc2VsZWN0ZWQgPSB7IGdldDogZnVuY3Rpb24gKGUpIHsgdmFyIHQgPSBlLnBhcmVudE5vZGU7IHJldHVybiB0ICYmIHQucGFyZW50Tm9kZSAmJiB0LnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleCwgbnVsbCB9LCBzZXQ6IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gZS5wYXJlbnROb2RlOyB0ICYmICh0LnNlbGVjdGVkSW5kZXgsIHQucGFyZW50Tm9kZSAmJiB0LnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleCkgfSB9KSwgdy5lYWNoKFsidGFiSW5kZXgiLCAicmVhZE9ubHkiLCAibWF4TGVuZ3RoIiwgImNlbGxTcGFjaW5nIiwgImNlbGxQYWRkaW5nIiwgInJvd1NwYW4iLCAiY29sU3BhbiIsICJ1c2VNYXAiLCAiZnJhbWVCb3JkZXIiLCAiY29udGVudEVkaXRhYmxlIl0sIGZ1bmN0aW9uICgpIHsgdy5wcm9wRml4W3RoaXMudG9Mb3dlckNhc2UoKV0gPSB0aGlzIH0pOyBmdW5jdGlvbiBvdChlKSB7IHJldHVybiAoZS5tYXRjaChJKSB8fCBbXSkuam9pbigiICIpIH0gZnVuY3Rpb24gYXQoZSkgeyByZXR1cm4gZS5nZXRBdHRyaWJ1dGUgJiYgZS5nZXRBdHRyaWJ1dGUoImNsYXNzIikgfHwgIiIgfSBmdW5jdGlvbiB1dChlKSB7IHJldHVybiBBcnJheS5pc0FycmF5KGUpID8gZSA6ICJzdHJpbmciID09IHR5cGVvZiBlID8gZS5tYXRjaChJKSB8fCBbXSA6IFtdIH0gdy5mbi5leHRlbmQoeyBhZGRDbGFzczogZnVuY3Rpb24gKGUpIHsgdmFyIHQsIG4sIHIsIGksIG8sIGEsIHUsIHMgPSAwOyBpZiAoZyhlKSkgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAodCkgeyB3KHRoaXMpLmFkZENsYXNzKGUuY2FsbCh0aGlzLCB0LCBhdCh0aGlzKSkpIH0pOyBpZiAoKHQgPSB1dChlKSkubGVuZ3RoKSB3aGlsZSAobiA9IHRoaXNbcysrXSkgaWYgKGkgPSBhdChuKSwgciA9IDEgPT09IG4ubm9kZVR5cGUgJiYgIiAiICsgb3QoaSkgKyAiICIpIHsgYSA9IDA7IHdoaWxlIChvID0gdFthKytdKSByLmluZGV4T2YoIiAiICsgbyArICIgIikgPCAwICYmIChyICs9IG8gKyAiICIpOyBpICE9PSAodSA9IG90KHIpKSAmJiBuLnNldEF0dHJpYnV0ZSgiY2xhc3MiLCB1KSB9IHJldHVybiB0aGlzIH0sIHJlbW92ZUNsYXNzOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgbiwgciwgaSwgbywgYSwgdSwgcyA9IDA7IGlmIChnKGUpKSByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICh0KSB7IHcodGhpcykucmVtb3ZlQ2xhc3MoZS5jYWxsKHRoaXMsIHQsIGF0KHRoaXMpKSkgfSk7IGlmICghYXJndW1lbnRzLmxlbmd0aCkgcmV0dXJuIHRoaXMuYXR0cigiY2xhc3MiLCAiIik7IGlmICgodCA9IHV0KGUpKS5sZW5ndGgpIHdoaWxlIChuID0gdGhpc1tzKytdKSBpZiAoaSA9IGF0KG4pLCByID0gMSA9PT0gbi5ub2RlVHlwZSAmJiAiICIgKyBvdChpKSArICIgIikgeyBhID0gMDsgd2hpbGUgKG8gPSB0W2ErK10pIHdoaWxlIChyLmluZGV4T2YoIiAiICsgbyArICIgIikgPiAtMSkgciA9IHIucmVwbGFjZSgiICIgKyBvICsgIiAiLCAiICIpOyBpICE9PSAodSA9IG90KHIpKSAmJiBuLnNldEF0dHJpYnV0ZSgiY2xhc3MiLCB1KSB9IHJldHVybiB0aGlzIH0sIHRvZ2dsZUNsYXNzOiBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IHR5cGVvZiBlLCByID0gInN0cmluZyIgPT09IG4gfHwgQXJyYXkuaXNBcnJheShlKTsgcmV0dXJuICJib29sZWFuIiA9PSB0eXBlb2YgdCAmJiByID8gdCA/IHRoaXMuYWRkQ2xhc3MoZSkgOiB0aGlzLnJlbW92ZUNsYXNzKGUpIDogZyhlKSA/IHRoaXMuZWFjaChmdW5jdGlvbiAobikgeyB3KHRoaXMpLnRvZ2dsZUNsYXNzKGUuY2FsbCh0aGlzLCBuLCBhdCh0aGlzKSwgdCksIHQpIH0pIDogdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHsgdmFyIHQsIGksIG8sIGE7IGlmIChyKSB7IGkgPSAwLCBvID0gdyh0aGlzKSwgYSA9IHV0KGUpOyB3aGlsZSAodCA9IGFbaSsrXSkgby5oYXNDbGFzcyh0KSA/IG8ucmVtb3ZlQ2xhc3ModCkgOiBvLmFkZENsYXNzKHQpIH0gZWxzZSB2b2lkIDAgIT09IGUgJiYgImJvb2xlYW4iICE9PSBuIHx8ICgodCA9IGF0KHRoaXMpKSAmJiBLLnNldCh0aGlzLCAiX19jbGFzc05hbWVfXyIsIHQpLCB0aGlzLnNldEF0dHJpYnV0ZSAmJiB0aGlzLnNldEF0dHJpYnV0ZSgiY2xhc3MiLCB0IHx8ICExID09PSBlID8gIiIgOiBLLmdldCh0aGlzLCAiX19jbGFzc05hbWVfXyIpIHx8ICIiKSkgfSkgfSwgaGFzQ2xhc3M6IGZ1bmN0aW9uIChlKSB7IHZhciB0LCBuLCByID0gMDsgdCA9ICIgIiArIGUgKyAiICI7IHdoaWxlIChuID0gdGhpc1tyKytdKSBpZiAoMSA9PT0gbi5ub2RlVHlwZSAmJiAoIiAiICsgb3QoYXQobikpICsgIiAiKS5pbmRleE9mKHQpID4gLTEpIHJldHVybiAhMDsgcmV0dXJuICExIH0gfSk7IHZhciBzdCA9IC9cci9nOyB3LmZuLmV4dGVuZCh7IHZhbDogZnVuY3Rpb24gKGUpIHsgdmFyIHQsIG4sIHIsIGkgPSB0aGlzWzBdOyB7IGlmIChhcmd1bWVudHMubGVuZ3RoKSByZXR1cm4gciA9IGcoZSksIHRoaXMuZWFjaChmdW5jdGlvbiAobikgeyB2YXIgaTsgMSA9PT0gdGhpcy5ub2RlVHlwZSAmJiAobnVsbCA9PSAoaSA9IHIgPyBlLmNhbGwodGhpcywgbiwgdyh0aGlzKS52YWwoKSkgOiBlKSA/IGkgPSAiIiA6ICJudW1iZXIiID09IHR5cGVvZiBpID8gaSArPSAiIiA6IEFycmF5LmlzQXJyYXkoaSkgJiYgKGkgPSB3Lm1hcChpLCBmdW5jdGlvbiAoZSkgeyByZXR1cm4gbnVsbCA9PSBlID8gIiIgOiBlICsgIiIgfSkpLCAodCA9IHcudmFsSG9va3NbdGhpcy50eXBlXSB8fCB3LnZhbEhvb2tzW3RoaXMubm9kZU5hbWUudG9Mb3dlckNhc2UoKV0pICYmICJzZXQiIGluIHQgJiYgdm9pZCAwICE9PSB0LnNldCh0aGlzLCBpLCAidmFsdWUiKSB8fCAodGhpcy52YWx1ZSA9IGkpKSB9KTsgaWYgKGkpIHJldHVybiAodCA9IHcudmFsSG9va3NbaS50eXBlXSB8fCB3LnZhbEhvb2tzW2kubm9kZU5hbWUudG9Mb3dlckNhc2UoKV0pICYmICJnZXQiIGluIHQgJiYgdm9pZCAwICE9PSAobiA9IHQuZ2V0KGksICJ2YWx1ZSIpKSA/IG4gOiAic3RyaW5nIiA9PSB0eXBlb2YgKG4gPSBpLnZhbHVlKSA/IG4ucmVwbGFjZShzdCwgIiIpIDogbnVsbCA9PSBuID8gIiIgOiBuIH0gfSB9KSwgdy5leHRlbmQoeyB2YWxIb29rczogeyBvcHRpb246IHsgZ2V0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IHcuZmluZC5hdHRyKGUsICJ2YWx1ZSIpOyByZXR1cm4gbnVsbCAhPSB0ID8gdCA6IG90KHcudGV4dChlKSkgfSB9LCBzZWxlY3Q6IHsgZ2V0OiBmdW5jdGlvbiAoZSkgeyB2YXIgdCwgbiwgciwgaSA9IGUub3B0aW9ucywgbyA9IGUuc2VsZWN0ZWRJbmRleCwgYSA9ICJzZWxlY3Qtb25lIiA9PT0gZS50eXBlLCB1ID0gYSA/IG51bGwgOiBbXSwgcyA9IGEgPyBvICsgMSA6IGkubGVuZ3RoOyBmb3IgKHIgPSBvIDwgMCA/IHMgOiBhID8gbyA6IDA7IHIgPCBzOyByKyspaWYgKCgobiA9IGlbcl0pLnNlbGVjdGVkIHx8IHIgPT09IG8pICYmICFuLmRpc2FibGVkICYmICghbi5wYXJlbnROb2RlLmRpc2FibGVkIHx8ICFEKG4ucGFyZW50Tm9kZSwgIm9wdGdyb3VwIikpKSB7IGlmICh0ID0gdyhuKS52YWwoKSwgYSkgcmV0dXJuIHQ7IHUucHVzaCh0KSB9IHJldHVybiB1IH0sIHNldDogZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIsIGkgPSBlLm9wdGlvbnMsIG8gPSB3Lm1ha2VBcnJheSh0KSwgYSA9IGkubGVuZ3RoOyB3aGlsZSAoYS0tKSAoKHIgPSBpW2FdKS5zZWxlY3RlZCA9IHcuaW5BcnJheSh3LnZhbEhvb2tzLm9wdGlvbi5nZXQociksIG8pID4gLTEpICYmIChuID0gITApOyByZXR1cm4gbiB8fCAoZS5zZWxlY3RlZEluZGV4ID0gLTEpLCBvIH0gfSB9IH0pLCB3LmVhY2goWyJyYWRpbyIsICJjaGVja2JveCJdLCBmdW5jdGlvbiAoKSB7IHcudmFsSG9va3NbdGhpc10gPSB7IHNldDogZnVuY3Rpb24gKGUsIHQpIHsgaWYgKEFycmF5LmlzQXJyYXkodCkpIHJldHVybiBlLmNoZWNrZWQgPSB3LmluQXJyYXkodyhlKS52YWwoKSwgdCkgPiAtMSB9IH0sIGguY2hlY2tPbiB8fCAody52YWxIb29rc1t0aGlzXS5nZXQgPSBmdW5jdGlvbiAoZSkgeyByZXR1cm4gbnVsbCA9PT0gZS5nZXRBdHRyaWJ1dGUoInZhbHVlIikgPyAib24iIDogZS52YWx1ZSB9KSB9KSwgaC5mb2N1c2luID0gIm9uZm9jdXNpbiIgaW4gZTsgdmFyIGx0ID0gL14oPzpmb2N1c2luZm9jdXN8Zm9jdXNvdXRibHVyKSQvLCBjdCA9IGZ1bmN0aW9uIChlKSB7IGUuc3RvcFByb3BhZ2F0aW9uKCkgfTsgdy5leHRlbmQody5ldmVudCwgeyB0cmlnZ2VyOiBmdW5jdGlvbiAodCwgbiwgaSwgbykgeyB2YXIgYSwgdSwgcywgbCwgYywgZCwgcCwgaCwgeSA9IFtpIHx8IHJdLCBtID0gZi5jYWxsKHQsICJ0eXBlIikgPyB0LnR5cGUgOiB0LCBiID0gZi5jYWxsKHQsICJuYW1lc3BhY2UiKSA/IHQubmFtZXNwYWNlLnNwbGl0KCIuIikgOiBbXTsgaWYgKHUgPSBoID0gcyA9IGkgPSBpIHx8IHIsIDMgIT09IGkubm9kZVR5cGUgJiYgOCAhPT0gaS5ub2RlVHlwZSAmJiAhbHQudGVzdChtICsgdy5ldmVudC50cmlnZ2VyZWQpICYmIChtLmluZGV4T2YoIi4iKSA+IC0xICYmIChtID0gKGIgPSBtLnNwbGl0KCIuIikpLnNoaWZ0KCksIGIuc29ydCgpKSwgYyA9IG0uaW5kZXhPZigiOiIpIDwgMCAmJiAib24iICsgbSwgdCA9IHRbdy5leHBhbmRvXSA/IHQgOiBuZXcgdy5FdmVudChtLCAib2JqZWN0IiA9PSB0eXBlb2YgdCAmJiB0KSwgdC5pc1RyaWdnZXIgPSBvID8gMiA6IDMsIHQubmFtZXNwYWNlID0gYi5qb2luKCIuIiksIHQucm5hbWVzcGFjZSA9IHQubmFtZXNwYWNlID8gbmV3IFJlZ0V4cCgiKF58XFwuKSIgKyBiLmpvaW4oIlxcLig/Oi4qXFwufCkiKSArICIoXFwufCQpIikgOiBudWxsLCB0LnJlc3VsdCA9IHZvaWQgMCwgdC50YXJnZXQgfHwgKHQudGFyZ2V0ID0gaSksIG4gPSBudWxsID09IG4gPyBbdF0gOiB3Lm1ha2VBcnJheShuLCBbdF0pLCBwID0gdy5ldmVudC5zcGVjaWFsW21dIHx8IHt9LCBvIHx8ICFwLnRyaWdnZXIgfHwgITEgIT09IHAudHJpZ2dlci5hcHBseShpLCBuKSkpIHsgaWYgKCFvICYmICFwLm5vQnViYmxlICYmICF2KGkpKSB7IGZvciAobCA9IHAuZGVsZWdhdGVUeXBlIHx8IG0sIGx0LnRlc3QobCArIG0pIHx8ICh1ID0gdS5wYXJlbnROb2RlKTsgdTsgdSA9IHUucGFyZW50Tm9kZSl5LnB1c2godSksIHMgPSB1OyBzID09PSAoaS5vd25lckRvY3VtZW50IHx8IHIpICYmIHkucHVzaChzLmRlZmF1bHRWaWV3IHx8IHMucGFyZW50V2luZG93IHx8IGUpIH0gYSA9IDA7IHdoaWxlICgodSA9IHlbYSsrXSkgJiYgIXQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSkgaCA9IHUsIHQudHlwZSA9IGEgPiAxID8gbCA6IHAuYmluZFR5cGUgfHwgbSwgKGQgPSAoSy5nZXQodSwgImV2ZW50cyIpIHx8IHt9KVt0LnR5cGVdICYmIEsuZ2V0KHUsICJoYW5kbGUiKSkgJiYgZC5hcHBseSh1LCBuKSwgKGQgPSBjICYmIHVbY10pICYmIGQuYXBwbHkgJiYgWSh1KSAmJiAodC5yZXN1bHQgPSBkLmFwcGx5KHUsIG4pLCAhMSA9PT0gdC5yZXN1bHQgJiYgdC5wcmV2ZW50RGVmYXVsdCgpKTsgcmV0dXJuIHQudHlwZSA9IG0sIG8gfHwgdC5pc0RlZmF1bHRQcmV2ZW50ZWQoKSB8fCBwLl9kZWZhdWx0ICYmICExICE9PSBwLl9kZWZhdWx0LmFwcGx5KHkucG9wKCksIG4pIHx8ICFZKGkpIHx8IGMgJiYgZyhpW21dKSAmJiAhdihpKSAmJiAoKHMgPSBpW2NdKSAmJiAoaVtjXSA9IG51bGwpLCB3LmV2ZW50LnRyaWdnZXJlZCA9IG0sIHQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSAmJiBoLmFkZEV2ZW50TGlzdGVuZXIobSwgY3QpLCBpW21dKCksIHQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSAmJiBoLnJlbW92ZUV2ZW50TGlzdGVuZXIobSwgY3QpLCB3LmV2ZW50LnRyaWdnZXJlZCA9IHZvaWQgMCwgcyAmJiAoaVtjXSA9IHMpKSwgdC5yZXN1bHQgfSB9LCBzaW11bGF0ZTogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIgPSB3LmV4dGVuZChuZXcgdy5FdmVudCwgbiwgeyB0eXBlOiBlLCBpc1NpbXVsYXRlZDogITAgfSk7IHcuZXZlbnQudHJpZ2dlcihyLCBudWxsLCB0KSB9IH0pLCB3LmZuLmV4dGVuZCh7IHRyaWdnZXI6IGZ1bmN0aW9uIChlLCB0KSB7IHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24gKCkgeyB3LmV2ZW50LnRyaWdnZXIoZSwgdCwgdGhpcykgfSkgfSwgdHJpZ2dlckhhbmRsZXI6IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuID0gdGhpc1swXTsgaWYgKG4pIHJldHVybiB3LmV2ZW50LnRyaWdnZXIoZSwgdCwgbiwgITApIH0gfSksIGguZm9jdXNpbiB8fCB3LmVhY2goeyBmb2N1czogImZvY3VzaW4iLCBibHVyOiAiZm9jdXNvdXQiIH0sIGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuID0gZnVuY3Rpb24gKGUpIHsgdy5ldmVudC5zaW11bGF0ZSh0LCBlLnRhcmdldCwgdy5ldmVudC5maXgoZSkpIH07IHcuZXZlbnQuc3BlY2lhbFt0XSA9IHsgc2V0dXA6IGZ1bmN0aW9uICgpIHsgdmFyIHIgPSB0aGlzLm93bmVyRG9jdW1lbnQgfHwgdGhpcywgaSA9IEsuYWNjZXNzKHIsIHQpOyBpIHx8IHIuYWRkRXZlbnRMaXN0ZW5lcihlLCBuLCAhMCksIEsuYWNjZXNzKHIsIHQsIChpIHx8IDApICsgMSkgfSwgdGVhcmRvd246IGZ1bmN0aW9uICgpIHsgdmFyIHIgPSB0aGlzLm93bmVyRG9jdW1lbnQgfHwgdGhpcywgaSA9IEsuYWNjZXNzKHIsIHQpIC0gMTsgaSA/IEsuYWNjZXNzKHIsIHQsIGkpIDogKHIucmVtb3ZlRXZlbnRMaXN0ZW5lcihlLCBuLCAhMCksIEsucmVtb3ZlKHIsIHQpKSB9IH0gfSk7IHZhciBmdCA9IC9cW1xdJC8sIGR0ID0gL1xyP1xuL2csIHB0ID0gL14oPzpzdWJtaXR8YnV0dG9ufGltYWdlfHJlc2V0fGZpbGUpJC9pLCBodCA9IC9eKD86aW5wdXR8c2VsZWN0fHRleHRhcmVhfGtleWdlbikvaTsgZnVuY3Rpb24gZ3QoZSwgdCwgbiwgcikgeyB2YXIgaTsgaWYgKEFycmF5LmlzQXJyYXkodCkpIHcuZWFjaCh0LCBmdW5jdGlvbiAodCwgaSkgeyBuIHx8IGZ0LnRlc3QoZSkgPyByKGUsIGkpIDogZ3QoZSArICJbIiArICgib2JqZWN0IiA9PSB0eXBlb2YgaSAmJiBudWxsICE9IGkgPyB0IDogIiIpICsgIl0iLCBpLCBuLCByKSB9KTsgZWxzZSBpZiAobiB8fCAib2JqZWN0IiAhPT0gYih0KSkgcihlLCB0KTsgZWxzZSBmb3IgKGkgaW4gdCkgZ3QoZSArICJbIiArIGkgKyAiXSIsIHRbaV0sIG4sIHIpIH0gdy5wYXJhbSA9IGZ1bmN0aW9uIChlLCB0KSB7IHZhciBuLCByID0gW10sIGkgPSBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9IGcodCkgPyB0KCkgOiB0OyByW3IubGVuZ3RoXSA9IGVuY29kZVVSSUNvbXBvbmVudChlKSArICI9IiArIGVuY29kZVVSSUNvbXBvbmVudChudWxsID09IG4gPyAiIiA6IG4pIH07IGlmIChBcnJheS5pc0FycmF5KGUpIHx8IGUuanF1ZXJ5ICYmICF3LmlzUGxhaW5PYmplY3QoZSkpIHcuZWFjaChlLCBmdW5jdGlvbiAoKSB7IGkodGhpcy5uYW1lLCB0aGlzLnZhbHVlKSB9KTsgZWxzZSBmb3IgKG4gaW4gZSkgZ3QobiwgZVtuXSwgdCwgaSk7IHJldHVybiByLmpvaW4oIiYiKSB9LCB3LmZuLmV4dGVuZCh7IHNlcmlhbGl6ZTogZnVuY3Rpb24gKCkgeyByZXR1cm4gdy5wYXJhbSh0aGlzLnNlcmlhbGl6ZUFycmF5KCkpIH0sIHNlcmlhbGl6ZUFycmF5OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLm1hcChmdW5jdGlvbiAoKSB7IHZhciBlID0gdy5wcm9wKHRoaXMsICJlbGVtZW50cyIpOyByZXR1cm4gZSA/IHcubWFrZUFycmF5KGUpIDogdGhpcyB9KS5maWx0ZXIoZnVuY3Rpb24gKCkgeyB2YXIgZSA9IHRoaXMudHlwZTsgcmV0dXJuIHRoaXMubmFtZSAmJiAhdyh0aGlzKS5pcygiOmRpc2FibGVkIikgJiYgaHQudGVzdCh0aGlzLm5vZGVOYW1lKSAmJiAhcHQudGVzdChlKSAmJiAodGhpcy5jaGVja2VkIHx8ICFkZS50ZXN0KGUpKSB9KS5tYXAoZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4gPSB3KHRoaXMpLnZhbCgpOyByZXR1cm4gbnVsbCA9PSBuID8gbnVsbCA6IEFycmF5LmlzQXJyYXkobikgPyB3Lm1hcChuLCBmdW5jdGlvbiAoZSkgeyByZXR1cm4geyBuYW1lOiB0Lm5hbWUsIHZhbHVlOiBlLnJlcGxhY2UoZHQsICJcclxuIikgfSB9KSA6IHsgbmFtZTogdC5uYW1lLCB2YWx1ZTogbi5yZXBsYWNlKGR0LCAiXHJcbiIpIH0gfSkuZ2V0KCkgfSB9KSwgdy5mbi5leHRlbmQoeyB3cmFwQWxsOiBmdW5jdGlvbiAoZSkgeyB2YXIgdDsgcmV0dXJuIHRoaXNbMF0gJiYgKGcoZSkgJiYgKGUgPSBlLmNhbGwodGhpc1swXSkpLCB0ID0gdyhlLCB0aGlzWzBdLm93bmVyRG9jdW1lbnQpLmVxKDApLmNsb25lKCEwKSwgdGhpc1swXS5wYXJlbnROb2RlICYmIHQuaW5zZXJ0QmVmb3JlKHRoaXNbMF0pLCB0Lm1hcChmdW5jdGlvbiAoKSB7IHZhciBlID0gdGhpczsgd2hpbGUgKGUuZmlyc3RFbGVtZW50Q2hpbGQpIGUgPSBlLmZpcnN0RWxlbWVudENoaWxkOyByZXR1cm4gZSB9KS5hcHBlbmQodGhpcykpLCB0aGlzIH0sIHdyYXBJbm5lcjogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIGcoZSkgPyB0aGlzLmVhY2goZnVuY3Rpb24gKHQpIHsgdyh0aGlzKS53cmFwSW5uZXIoZS5jYWxsKHRoaXMsIHQpKSB9KSA6IHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7IHZhciB0ID0gdyh0aGlzKSwgbiA9IHQuY29udGVudHMoKTsgbi5sZW5ndGggPyBuLndyYXBBbGwoZSkgOiB0LmFwcGVuZChlKSB9KSB9LCB3cmFwOiBmdW5jdGlvbiAoZSkgeyB2YXIgdCA9IGcoZSk7IHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24gKG4pIHsgdyh0aGlzKS53cmFwQWxsKHQgPyBlLmNhbGwodGhpcywgbikgOiBlKSB9KSB9LCB1bndyYXA6IGZ1bmN0aW9uIChlKSB7IHJldHVybiB0aGlzLnBhcmVudChlKS5ub3QoImJvZHkiKS5lYWNoKGZ1bmN0aW9uICgpIHsgdyh0aGlzKS5yZXBsYWNlV2l0aCh0aGlzLmNoaWxkTm9kZXMpIH0pLCB0aGlzIH0gfSksIHcuZXhwci5wc2V1ZG9zLmhpZGRlbiA9IGZ1bmN0aW9uIChlKSB7IHJldHVybiAhdy5leHByLnBzZXVkb3MudmlzaWJsZShlKSB9LCB3LmV4cHIucHNldWRvcy52aXNpYmxlID0gZnVuY3Rpb24gKGUpIHsgcmV0dXJuICEhKGUub2Zmc2V0V2lkdGggfHwgZS5vZmZzZXRIZWlnaHQgfHwgZS5nZXRDbGllbnRSZWN0cygpLmxlbmd0aCkgfSwgaC5jcmVhdGVIVE1MRG9jdW1lbnQgPSBmdW5jdGlvbiAoKSB7IHZhciBlID0gci5pbXBsZW1lbnRhdGlvbi5jcmVhdGVIVE1MRG9jdW1lbnQoIiIpLmJvZHk7IHJldHVybiBlLmlubmVySFRNTCA9ICI8Zm9ybT48L2Zvcm0+PGZvcm0+PC9mb3JtPiIsIDIgPT09IGUuY2hpbGROb2Rlcy5sZW5ndGggfSgpLCB3LnBhcnNlSFRNTCA9IGZ1bmN0aW9uIChlLCB0LCBuKSB7IGlmICgic3RyaW5nIiAhPSB0eXBlb2YgZSkgcmV0dXJuIFtdOyAiYm9vbGVhbiIgPT0gdHlwZW9mIHQgJiYgKG4gPSB0LCB0ID0gITEpOyB2YXIgaSwgbywgYTsgcmV0dXJuIHQgfHwgKGguY3JlYXRlSFRNTERvY3VtZW50ID8gKChpID0gKHQgPSByLmltcGxlbWVudGF0aW9uLmNyZWF0ZUhUTUxEb2N1bWVudCgiIikpLmNyZWF0ZUVsZW1lbnQoImJhc2UiKSkuaHJlZiA9IHIubG9jYXRpb24uaHJlZiwgdC5oZWFkLmFwcGVuZENoaWxkKGkpKSA6IHQgPSByKSwgbyA9IFMuZXhlYyhlKSwgYSA9ICFuICYmIFtdLCBvID8gW3QuY3JlYXRlRWxlbWVudChvWzFdKV0gOiAobyA9IGJlKFtlXSwgdCwgYSksIGEgJiYgYS5sZW5ndGggJiYgdyhhKS5yZW1vdmUoKSwgdy5tZXJnZShbXSwgby5jaGlsZE5vZGVzKSkgfSwgdy5vZmZzZXQgPSB7IHNldE9mZnNldDogZnVuY3Rpb24gKGUsIHQsIG4pIHsgdmFyIHIsIGksIG8sIGEsIHUsIHMsIGwsIGMgPSB3LmNzcyhlLCAicG9zaXRpb24iKSwgZiA9IHcoZSksIGQgPSB7fTsgInN0YXRpYyIgPT09IGMgJiYgKGUuc3R5bGUucG9zaXRpb24gPSAicmVsYXRpdmUiKSwgdSA9IGYub2Zmc2V0KCksIG8gPSB3LmNzcyhlLCAidG9wIiksIHMgPSB3LmNzcyhlLCAibGVmdCIpLCAobCA9ICgiYWJzb2x1dGUiID09PSBjIHx8ICJmaXhlZCIgPT09IGMpICYmIChvICsgcykuaW5kZXhPZigiYXV0byIpID4gLTEpID8gKGEgPSAociA9IGYucG9zaXRpb24oKSkudG9wLCBpID0gci5sZWZ0KSA6IChhID0gcGFyc2VGbG9hdChvKSB8fCAwLCBpID0gcGFyc2VGbG9hdChzKSB8fCAwKSwgZyh0KSAmJiAodCA9IHQuY2FsbChlLCBuLCB3LmV4dGVuZCh7fSwgdSkpKSwgbnVsbCAhPSB0LnRvcCAmJiAoZC50b3AgPSB0LnRvcCAtIHUudG9wICsgYSksIG51bGwgIT0gdC5sZWZ0ICYmIChkLmxlZnQgPSB0LmxlZnQgLSB1LmxlZnQgKyBpKSwgInVzaW5nIiBpbiB0ID8gdC51c2luZy5jYWxsKGUsIGQpIDogZi5jc3MoZCkgfSB9LCB3LmZuLmV4dGVuZCh7IG9mZnNldDogZnVuY3Rpb24gKGUpIHsgaWYgKGFyZ3VtZW50cy5sZW5ndGgpIHJldHVybiB2b2lkIDAgPT09IGUgPyB0aGlzIDogdGhpcy5lYWNoKGZ1bmN0aW9uICh0KSB7IHcub2Zmc2V0LnNldE9mZnNldCh0aGlzLCBlLCB0KSB9KTsgdmFyIHQsIG4sIHIgPSB0aGlzWzBdOyBpZiAocikgcmV0dXJuIHIuZ2V0Q2xpZW50UmVjdHMoKS5sZW5ndGggPyAodCA9IHIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksIG4gPSByLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcsIHsgdG9wOiB0LnRvcCArIG4ucGFnZVlPZmZzZXQsIGxlZnQ6IHQubGVmdCArIG4ucGFnZVhPZmZzZXQgfSkgOiB7IHRvcDogMCwgbGVmdDogMCB9IH0sIHBvc2l0aW9uOiBmdW5jdGlvbiAoKSB7IGlmICh0aGlzWzBdKSB7IHZhciBlLCB0LCBuLCByID0gdGhpc1swXSwgaSA9IHsgdG9wOiAwLCBsZWZ0OiAwIH07IGlmICgiZml4ZWQiID09PSB3LmNzcyhyLCAicG9zaXRpb24iKSkgdCA9IHIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7IGVsc2UgeyB0ID0gdGhpcy5vZmZzZXQoKSwgbiA9IHIub3duZXJEb2N1bWVudCwgZSA9IHIub2Zmc2V0UGFyZW50IHx8IG4uZG9jdW1lbnRFbGVtZW50OyB3aGlsZSAoZSAmJiAoZSA9PT0gbi5ib2R5IHx8IGUgPT09IG4uZG9jdW1lbnRFbGVtZW50KSAmJiAic3RhdGljIiA9PT0gdy5jc3MoZSwgInBvc2l0aW9uIikpIGUgPSBlLnBhcmVudE5vZGU7IGUgJiYgZSAhPT0gciAmJiAxID09PSBlLm5vZGVUeXBlICYmICgoaSA9IHcoZSkub2Zmc2V0KCkpLnRvcCArPSB3LmNzcyhlLCAiYm9yZGVyVG9wV2lkdGgiLCAhMCksIGkubGVmdCArPSB3LmNzcyhlLCAiYm9yZGVyTGVmdFdpZHRoIiwgITApKSB9IHJldHVybiB7IHRvcDogdC50b3AgLSBpLnRvcCAtIHcuY3NzKHIsICJtYXJnaW5Ub3AiLCAhMCksIGxlZnQ6IHQubGVmdCAtIGkubGVmdCAtIHcuY3NzKHIsICJtYXJnaW5MZWZ0IiwgITApIH0gfSB9LCBvZmZzZXRQYXJlbnQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMubWFwKGZ1bmN0aW9uICgpIHsgdmFyIGUgPSB0aGlzLm9mZnNldFBhcmVudDsgd2hpbGUgKGUgJiYgInN0YXRpYyIgPT09IHcuY3NzKGUsICJwb3NpdGlvbiIpKSBlID0gZS5vZmZzZXRQYXJlbnQ7IHJldHVybiBlIHx8IHhlIH0pIH0gfSksIHcuZWFjaCh7IHNjcm9sbExlZnQ6ICJwYWdlWE9mZnNldCIsIHNjcm9sbFRvcDogInBhZ2VZT2Zmc2V0IiB9LCBmdW5jdGlvbiAoZSwgdCkgeyB2YXIgbiA9ICJwYWdlWU9mZnNldCIgPT09IHQ7IHcuZm5bZV0gPSBmdW5jdGlvbiAocikgeyByZXR1cm4gXyh0aGlzLCBmdW5jdGlvbiAoZSwgciwgaSkgeyB2YXIgbzsgaWYgKHYoZSkgPyBvID0gZSA6IDkgPT09IGUubm9kZVR5cGUgJiYgKG8gPSBlLmRlZmF1bHRWaWV3KSwgdm9pZCAwID09PSBpKSByZXR1cm4gbyA/IG9bdF0gOiBlW3JdOyBvID8gby5zY3JvbGxUbyhuID8gby5wYWdlWE9mZnNldCA6IGksIG4gPyBpIDogby5wYWdlWU9mZnNldCkgOiBlW3JdID0gaSB9LCBlLCByLCBhcmd1bWVudHMubGVuZ3RoKSB9IH0pLCB3LmVhY2goWyJ0b3AiLCAibGVmdCJdLCBmdW5jdGlvbiAoZSwgdCkgeyB3LmNzc0hvb2tzW3RdID0gemUoaC5waXhlbFBvc2l0aW9uLCBmdW5jdGlvbiAoZSwgbikgeyBpZiAobikgcmV0dXJuIG4gPSBGZShlLCB0KSwgTWUudGVzdChuKSA/IHcoZSkucG9zaXRpb24oKVt0XSArICJweCIgOiBuIH0pIH0pLCB3LmVhY2goeyBIZWlnaHQ6ICJoZWlnaHQiLCBXaWR0aDogIndpZHRoIiB9LCBmdW5jdGlvbiAoZSwgdCkgeyB3LmVhY2goeyBwYWRkaW5nOiAiaW5uZXIiICsgZSwgY29udGVudDogdCwgIiI6ICJvdXRlciIgKyBlIH0sIGZ1bmN0aW9uIChuLCByKSB7IHcuZm5bcl0gPSBmdW5jdGlvbiAoaSwgbykgeyB2YXIgYSA9IGFyZ3VtZW50cy5sZW5ndGggJiYgKG4gfHwgImJvb2xlYW4iICE9IHR5cGVvZiBpKSwgdSA9IG4gfHwgKCEwID09PSBpIHx8ICEwID09PSBvID8gIm1hcmdpbiIgOiAiYm9yZGVyIik7IHJldHVybiBfKHRoaXMsIGZ1bmN0aW9uICh0LCBuLCBpKSB7IHZhciBvOyByZXR1cm4gdih0KSA/IDAgPT09IHIuaW5kZXhPZigib3V0ZXIiKSA/IHRbImlubmVyIiArIGVdIDogdC5kb2N1bWVudC5kb2N1bWVudEVsZW1lbnRbImNsaWVudCIgKyBlXSA6IDkgPT09IHQubm9kZVR5cGUgPyAobyA9IHQuZG9jdW1lbnRFbGVtZW50LCBNYXRoLm1heCh0LmJvZHlbInNjcm9sbCIgKyBlXSwgb1sic2Nyb2xsIiArIGVdLCB0LmJvZHlbIm9mZnNldCIgKyBlXSwgb1sib2Zmc2V0IiArIGVdLCBvWyJjbGllbnQiICsgZV0pKSA6IHZvaWQgMCA9PT0gaSA/IHcuY3NzKHQsIG4sIHUpIDogdy5zdHlsZSh0LCBuLCBpLCB1KSB9LCB0LCBhID8gaSA6IHZvaWQgMCwgYSkgfSB9KSB9KSwgdy5lYWNoKCJibHVyIGZvY3VzIGZvY3VzaW4gZm9jdXNvdXQgcmVzaXplIHNjcm9sbCBjbGljayBkYmxjbGljayBtb3VzZWRvd24gbW91c2V1cCBtb3VzZW1vdmUgbW91c2VvdmVyIG1vdXNlb3V0IG1vdXNlZW50ZXIgbW91c2VsZWF2ZSBjaGFuZ2Ugc2VsZWN0IHN1Ym1pdCBrZXlkb3duIGtleXByZXNzIGtleXVwIGNvbnRleHRtZW51Ii5zcGxpdCgiICIpLCBmdW5jdGlvbiAoZSwgdCkgeyB3LmZuW3RdID0gZnVuY3Rpb24gKGUsIG4pIHsgcmV0dXJuIGFyZ3VtZW50cy5sZW5ndGggPiAwID8gdGhpcy5vbih0LCBudWxsLCBlLCBuKSA6IHRoaXMudHJpZ2dlcih0KSB9IH0pLCB3LmZuLmV4dGVuZCh7IGhvdmVyOiBmdW5jdGlvbiAoZSwgdCkgeyByZXR1cm4gdGhpcy5tb3VzZWVudGVyKGUpLm1vdXNlbGVhdmUodCB8fCBlKSB9IH0pLCB3LmZuLmV4dGVuZCh7IGJpbmQ6IGZ1bmN0aW9uIChlLCB0LCBuKSB7IHJldHVybiB0aGlzLm9uKGUsIG51bGwsIHQsIG4pIH0sIHVuYmluZDogZnVuY3Rpb24gKGUsIHQpIHsgcmV0dXJuIHRoaXMub2ZmKGUsIG51bGwsIHQpIH0sIGRlbGVnYXRlOiBmdW5jdGlvbiAoZSwgdCwgbiwgcikgeyByZXR1cm4gdGhpcy5vbih0LCBlLCBuLCByKSB9LCB1bmRlbGVnYXRlOiBmdW5jdGlvbiAoZSwgdCwgbikgeyByZXR1cm4gMSA9PT0gYXJndW1lbnRzLmxlbmd0aCA/IHRoaXMub2ZmKGUsICIqKiIpIDogdGhpcy5vZmYodCwgZSB8fCAiKioiLCBuKSB9IH0pLCB3LnByb3h5ID0gZnVuY3Rpb24gKGUsIHQpIHsgdmFyIG4sIHIsIGk7IGlmICgic3RyaW5nIiA9PSB0eXBlb2YgdCAmJiAobiA9IGVbdF0sIHQgPSBlLCBlID0gbiksIGcoZSkpIHJldHVybiByID0gby5jYWxsKGFyZ3VtZW50cywgMiksIGkgPSBmdW5jdGlvbiAoKSB7IHJldHVybiBlLmFwcGx5KHQgfHwgdGhpcywgci5jb25jYXQoby5jYWxsKGFyZ3VtZW50cykpKSB9LCBpLmd1aWQgPSBlLmd1aWQgPSBlLmd1aWQgfHwgdy5ndWlkKysgLCBpIH0sIHcuaG9sZFJlYWR5ID0gZnVuY3Rpb24gKGUpIHsgZSA/IHcucmVhZHlXYWl0KysgOiB3LnJlYWR5KCEwKSB9LCB3LmlzQXJyYXkgPSBBcnJheS5pc0FycmF5LCB3LnBhcnNlSlNPTiA9IEpTT04ucGFyc2UsIHcubm9kZU5hbWUgPSBELCB3LmlzRnVuY3Rpb24gPSBnLCB3LmlzV2luZG93ID0gdiwgdy5jYW1lbENhc2UgPSBRLCB3LnR5cGUgPSBiLCB3Lm5vdyA9IERhdGUubm93LCB3LmlzTnVtZXJpYyA9IGZ1bmN0aW9uIChlKSB7IHZhciB0ID0gdy50eXBlKGUpOyByZXR1cm4gKCJudW1iZXIiID09PSB0IHx8ICJzdHJpbmciID09PSB0KSAmJiAhaXNOYU4oZSAtIHBhcnNlRmxvYXQoZSkpIH0sICJmdW5jdGlvbiIgPT0gdHlwZW9mIGRlZmluZSAmJiBkZWZpbmUuYW1kICYmIGRlZmluZSgianF1ZXJ5IiwgW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHcgfSk7IHZhciB2dCA9IGUualF1ZXJ5LCB5dCA9IGUuJDsgcmV0dXJuIHcubm9Db25mbGljdCA9IGZ1bmN0aW9uICh0KSB7IHJldHVybiBlLiQgPT09IHcgJiYgKGUuJCA9IHl0KSwgdCAmJiBlLmpRdWVyeSA9PT0gdyAmJiAoZS5qUXVlcnkgPSB2dCksIHcgfSwgdCB8fCAoZS5qUXVlcnkgPSBlLiQgPSB3KSwgdyB9KTs=\"") + packr.PackJSONBytes("./assets/default", "wails.js", "\"Ly8gV2FpbHMgcnVudGltZSBKUwoKKGZ1bmN0aW9uICgpIHsKCXdpbmRvdy53YWlscyA9IHdpbmRvdy53YWlscyB8fCB7CgkJJDoge30KCX07CgoJLyoqKioqKioqKioqKioqKioqKiBVdGlsaXR5IEZ1bmN0aW9ucyAqKioqKioqKioqKioqKioqKioqKioqKiovCgoJLy8gLS0tLS0tLS0tLS0tLS0gUmFuZG9tIC0tLS0tLS0tLS0tLS0tCgkvLyBBd2Vzb21lUmFuZG9tCglmdW5jdGlvbiBjcnlwdG9SYW5kb20oKSB7CgkJdmFyIGFycmF5ID0gbmV3IFVpbnQzMkFycmF5KDEpOwoJCXJldHVybiB3aW5kb3cuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhhcnJheSlbMF07Cgl9CgoJLy8gTE9MUmFuZG9tCglmdW5jdGlvbiBiYXNpY1JhbmRvbSgpIHsKCQlyZXR1cm4gTWF0aC5yYW5kb20oKSAqIDkwMDcxOTkyNTQ3NDA5OTE7Cgl9CgoJLy8gUGljayBvbmUgYmFzZWQgb24gYnJvd3NlciBjYXBhYmlsaXR5Cgl2YXIgcmFuZG9tRnVuYzsKCWlmICh3aW5kb3cuY3J5cHRvKSB7CgkJcmFuZG9tRnVuYyA9IGNyeXB0b1JhbmRvbTsKCX0gZWxzZSB7CgkJcmFuZG9tRnVuYyA9IGJhc2ljUmFuZG9tOwoJfQoKCS8vIC0tLS0tLS0tLS0tLS0tIElkZW50aWZpZXJzIC0tLS0tLS0tLS0tLS0tLQoKCWZ1bmN0aW9uIGlzVmFsaWRJZGVudGlmaWVyKG5hbWUpIHsKCQkvLyBEb24ndCB4c3MgeW91cnNlbGYgOi0pCgkJdHJ5IHsKCQkJbmV3IEZ1bmN0aW9uKCJ2YXIgIiArIG5hbWUpOwoJCQlyZXR1cm4gdHJ1ZQoJCX0gY2F0Y2ggKGUpIHsKCQkJcmV0dXJuIGZhbHNlCgkJfQoJfQoKCS8vIC0tLS0tLS0tLS0tLS0tIEpTIC0tLS0tLS0tLS0tLS0tLS0KCWZ1bmN0aW9uIGFkZFNjcmlwdChqcywgY2FsbGJhY2tJRCkgewoJCWNvbnNvbGUubG9nKCJBZGRpbmcgc2NyaXB0OiAiICsganMpCgkJdmFyIHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInNjcmlwdCIpOwoJCXNjcmlwdC50ZXh0ID0ganM7CgkJZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChzY3JpcHQpOwoJCWNvbnNvbGUubG9nKCJDYWxsaW5nIGJhY2sgd2l0aDoiICsgY2FsbGJhY2tJRCk7CgkJd2luZG93LndhaWxzLmV2ZW50cy5lbWl0KGNhbGxiYWNrSUQpOwoJfQoKCS8vIC0tLS0tLS0tLS0tLS0tIEhUTUwgLS0tLS0tLS0tLS0tLS0KCWZ1bmN0aW9uIHNldERvY3VtZW50KGh0bWwpIHsKCQlkb2N1bWVudC5vcGVuKCk7CgkJZG9jdW1lbnQud3JpdGUoaHRtbCk7CgkJZG9jdW1lbnQuY2xvc2UoKTsKCX0KCgkvLyAtLS0tLS0tLS0tLS0tLSBDU1MgLS0tLS0tLS0tLS0tLS0tCgkvLyBBZGFwdGVkIGZyb20gd2VidmlldyAtIHRoYW5rcyB6c2VyZ2UhCglmdW5jdGlvbiBpbmplY3RDU1MoY3NzKSB7CgkJdmFyIGVsZW0gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzdHlsZScpOwoJCWVsZW0uc2V0QXR0cmlidXRlKCd0eXBlJywgJ3RleHQvY3NzJyk7CgkJaWYgKGVsZW0uc3R5bGVTaGVldCkgewoJCQllbGVtLnN0eWxlU2hlZXQuY3NzVGV4dCA9IGNzczsKCQl9IGVsc2UgewoJCQllbGVtLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGNzcykpOwoJCX0KCQl2YXIgaGVhZCA9IGRvY3VtZW50LmhlYWQgfHwgZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2hlYWQnKVswXTsKCQloZWFkLmFwcGVuZENoaWxkKGVsZW0pCgl9CgoJLyoqKioqKioqKioqKioqKioqKioqKioqKiogQmluZGluZ3MgKioqKioqKioqKioqKioqKioqKioqKioqKi8KCgl2YXIgYmluZGluZ3NCYXNlUGF0aCA9IHdpbmRvdy53YWlscy4kOwoKCS8vIENyZWF0ZXMgdGhlIHBhdGggZ2l2ZW4gaW4gdGhlIGJpbmRpbmdzIHBhdGgKCWZ1bmN0aW9uIGFkZEJpbmRpbmdQYXRoKHBhdGhTZWN0aW9ucykgewoJCS8vIFN0YXJ0IGF0IHRoZSBiYXNlIHBhdGgKCQl2YXIgY3VycmVudFBhdGggPSBiaW5kaW5nc0Jhc2VQYXRoCgkJLy8gZm9yIGVhY2ggc2VjdGlvbiBvZiB0aGUgZ2l2ZW4gcGF0aAoJCWZvciAodmFyIHNlY3Rpb24gb2YgcGF0aFNlY3Rpb25zKSB7CgoJCQkvLyBJcyBzZWN0aW9uIGEgdmFsaWQgamF2YXNjcmlwdCBpZGVudGlmaWVyPwoJCQlpZiAoIWlzVmFsaWRJZGVudGlmaWVyKHNlY3Rpb24pKSB7CgkJCQl2YXIgZXJyTWVzc2FnZSA9IHNlY3Rpb24gKyAiIGlzIG5vdCBhIHZhbGlkIGphdmFzY3JpcHQgaWRlbnRpZmllci4iCgkJCQl2YXIgZXJyID0gbmV3IEVycm9yKGVyck1lc3NhZ2UpCgkJCQlyZXR1cm4gW251bGwsIGVycl0KCQkJfQoKCQkJLy8gQWRkIGlmIGRvZXNuJ3QgZXhpc3QKCQkJaWYgKCFjdXJyZW50UGF0aFtzZWN0aW9uXSkgewoJCQkJY3VycmVudFBhdGhbc2VjdGlvbl0gPSB7fQoJCQl9CgkJCS8vIHVwZGF0ZSBjdXJyZW50IHBhdGggdG8gbmV3IHBhdGgKCQkJY3VycmVudFBhdGggPSBjdXJyZW50UGF0aFtzZWN0aW9uXQoJCX0KCQlyZXR1cm4gW2N1cnJlbnRQYXRoLCBudWxsXQoJfQoKCWZ1bmN0aW9uIG5ld0JpbmRpbmcoYmluZGluZ05hbWUpIHsKCgkJLy8gR2V0IGFsbCB0aGUgc2VjdGlvbnMgb2YgdGhlIGJpbmRpbmcKCQl2YXIgYmluZGluZ1NlY3Rpb25zID0gYmluZGluZ05hbWUuc3BsaXQoJy4nKTsKCgkJLy8gR2V0IHRoZSBhY3R1YWwgZnVuY3Rpb24vbWV0aG9kIGNhbGwgbmFtZQoJCXZhciBjYWxsTmFtZSA9IGJpbmRpbmdTZWN0aW9ucy5wb3AoKTsKCgkJLy8gQWRkIHBhdGggdG8gYmluZGluZwoJCVtwYXRoVG9CaW5kaW5nLCBlcnJdID0gYWRkQmluZGluZ1BhdGgoYmluZGluZ1NlY3Rpb25zKQoKCQlpZiAoZXJyICE9IG51bGwpIHsKCQkJLy8gV2UgbmVlZCB0byByZXR1cm4gYW4gZXJyb3IKCQkJLy8gd2luZG93LndhaWxzLmxvZy5FcnJvcigiIikKCQkJcmV0dXJuCgkJfQoKCQkvLyBBZGQgYmluZGluZyBjYWxsCgkJcGF0aFRvQmluZGluZ1tjYWxsTmFtZV0gPSBmdW5jdGlvbiAoKSB7CgoJCQkvLyBObyB0aW1lb3V0IGJ5IGRlZmF1bHQKCQkJdmFyIHRpbWVvdXQgPSAwOwoKCQkJLy8gQWN0dWFsIGZ1bmN0aW9uCgkJCWZ1bmN0aW9uIGR5bmFtaWMoKSB7CgkJCQl2YXIgYXJncyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKQoJCQkJcmV0dXJuIGNhbGwoYmluZGluZ05hbWUsIGFyZ3MsIHRpbWVvdXQpOwoJCQl9CgoJCQkvLyBBbGxvdyBzZXR0aW5nIHRpbWVvdXQgdG8gZnVuY3Rpb24KCQkJZHluYW1pYy5zZXRUaW1lb3V0ID0gZnVuY3Rpb24gKG5ld1RpbWVvdXQpIHsKCQkJCXRpbWVvdXQgPSBuZXdUaW1lb3V0OwoJCQl9CgoJCQkvLyBBbGxvdyBnZXR0aW5nIHRpbWVvdXQgdG8gZnVuY3Rpb24KCQkJZHluYW1pYy5nZXRUaW1lb3V0ID0gZnVuY3Rpb24gKCkgewoJCQkJcmV0dXJuIHRpbWVvdXQ7CgkJCX0KCgkJCXJldHVybiBkeW5hbWljOwoJCX0oKTsKCX0KCgkvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKCS8qKioqKioqKioqKioqKioqKioqKioqKioqKiogQ2FsbHMgKioqKioqKioqKioqKioqKioqKioqKioqKiovCgoJdmFyIGNhbGxiYWNrcyA9IHt9OwoKCS8vIENhbGwgc2VuZHMgYSBtZXNzYWdlIHRvIHRoZSBiYWNrZW5kIHRvIGNhbGwgdGhlIGJpbmRpbmcgd2l0aCB0aGUKCS8vIGdpdmVuIGRhdGEuIEEgcHJvbWlzZSBpcyByZXR1cm5lZCBhbmQgd2lsbCBiZSBjb21wbGV0ZWQgd2hlbiB0aGUKCS8vIGJhY2tlbmQgcmVzcG9uZHMuIFRoaXMgd2lsbCBiZSByZXNvbHZlZCB3aGVuIHRoZSBjYWxsIHdhcyBzdWNjZXNzZnVsCgkvLyBvciByZWplY3RlZCBpZiBhbiBlcnJvciBpcyBwYXNzZWQgYmFjay4KCS8vIFRoZXJlIGlzIGEgdGltZW91dCBtZWNoYW5pc20uIElmIHRoZSBjYWxsIGRvZXNuJ3QgcmVzcG9uZCBpbiB0aGUgZ2l2ZW4KCS8vIHRpbWUgKGluIG1pbGxpc2Vjb25kcykgdGhlbiB0aGUgcHJvbWlzZSBpcyByZWplY3RlZC4KCglmdW5jdGlvbiBjYWxsKGJpbmRpbmdOYW1lLCBkYXRhLCB0aW1lb3V0KSB7CgoJCS8vIFRpbWVvdXQgaW5maW5pdGUgYnkgZGVmYXVsdAoJCWlmICh0aW1lb3V0ID09IG51bGwgfHwgdGltZW91dCA9PSB1bmRlZmluZWQpIHsKCQkJdGltZW91dCA9IDA7CgkJfQoKCQkvLyBDcmVhdGUgYSBwcm9taXNlCgkJcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHsKCgkJCS8vIENyZWF0ZSBhIHVuaXF1ZSBjYWxsYmFja0lECgkJCXZhciBjYWxsYmFja0lEOwoJCQlkbyB7CgkJCQljYWxsYmFja0lEID0gYmluZGluZ05hbWUgKyAiLSIgKyByYW5kb21GdW5jKCk7CgkJCX0gd2hpbGUgKGNhbGxiYWNrc1tjYWxsYmFja0lEXSkKCgkJCS8vIFNldCB0aW1lb3V0CgkJCWlmICh0aW1lb3V0ID4gMCkgewoJCQkJdmFyIHRpbWVvdXRIYW5kbGUgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHsKCQkJCQlyZWplY3QoRXJyb3IoIkNhbGwgdG8gIiArIGJpbmRpbmdOYW1lICsgIiB0aW1lZCBvdXQuIFJlcXVlc3QgSUQ6ICIgKyBjYWxsYmFja0lEKSkKCQkJCX0sIHRpbWVvdXQpOwoJCQl9CgoJCQkvLyBTdG9yZSBjYWxsYmFjawoJCQljYWxsYmFja3NbY2FsbGJhY2tJRF0gPSB7CgkJCQl0aW1lb3V0SGFuZGxlOiB0aW1lb3V0SGFuZGxlLAoJCQkJcmVqZWN0OiByZWplY3QsCgkJCQlyZXNvbHZlOiByZXNvbHZlCgkJCX0KCQkJdHJ5IHsKCQkJCXZhciBwYXlsb2FkZGF0YSA9IEpTT04uc3RyaW5naWZ5KGRhdGEpCgkJCQkvLyBDcmVhdGUgdGhlIG1lc3NhZ2UKCQkJCW1lc3NhZ2UgPSB7CgkJCQkJdHlwZTogImNhbGwiLAoJCQkJCWNhbGxiYWNraWQ6IGNhbGxiYWNrSUQsCgkJCQkJcGF5bG9hZDogewoJCQkJCQliaW5kaW5nTmFtZTogYmluZGluZ05hbWUsCgkJCQkJCWRhdGE6IHBheWxvYWRkYXRhLAoJCQkJCX0KCQkJCX0KCgkJCQkvLyBNYWtlIHRoZSBjYWxsCgkJCQl2YXIgcGF5bG9hZCA9IEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpCgkJCQlleHRlcm5hbC5pbnZva2UocGF5bG9hZCk7CgkJCX0gY2F0Y2ggKGUpIHsKCQkJCWNvbnNvbGUuZXJyb3IoZSkKCQkJfQoJCX0pCgl9CgoKCS8vIENhbGxlZCBieSB0aGUgYmFja2VuZCB0byByZXR1cm4gZGF0YSB0byBhIHByZXZpb3VzbHkgY2FsbGVkCgkvLyBiaW5kaW5nIGludm9jYXRpb24KCWZ1bmN0aW9uIGNhbGxiYWNrKGluY29taW5nTWVzc2FnZSkgewoJCS8vIHdhaWxzLmxvZy5kZWJ1ZygiY2FsbGJhY2sgY2FsbGVkIHdpdGg6ICIgKyBpbmNvbWluZ01lc3NhZ2UpCgkJLy8gUGFyc2UgdGhlIG1lc3NhZ2UKCQl2YXIgbWVzc2FnZQoJCS8vIHdhaWxzLmxvZy5kZWJ1ZyhpbmNvbWluZ01lc3NhZ2UpCgkJdHJ5IHsKCQkJbWVzc2FnZSA9IEpTT04ucGFyc2UoaW5jb21pbmdNZXNzYWdlKQoJCX0gY2F0Y2ggKGUpIHsKCQkJd2FpbHMubG9nLmRlYnVnKCJJbnZhbGlkIEpTT04gcGFzc2VkIHRvIGNhbGxiYWNrOiAiICsgZS5tZXNzYWdlKQoJCQl3YWlscy5sb2cuZGVidWcoIk1lc3NhZ2U6ICIgKyBpbmNvbWluZ01lc3NhZ2UpCgkJCXJldHVybgoJCX0KCQljYWxsYmFja0lEID0gbWVzc2FnZS5jYWxsYmFja2lkCgkJY2FsbGJhY2tEYXRhID0gY2FsbGJhY2tzW2NhbGxiYWNrSURdCgkJaWYgKCFjYWxsYmFja0RhdGEpIHsKCQkJY29uc29sZS5lcnJvcigiQ2FsbGJhY2sgJyIgKyBjYWxsYmFja0lEICsgIicgbm90IHJlZ2lzdGVkISEhIikKCQkJcmV0dXJuCgkJfQoJCWNsZWFyVGltZW91dChjYWxsYmFja0RhdGEudGltZW91dEhhbmRsZSkKCQlkZWxldGUgY2FsbGJhY2tzW2NhbGxiYWNrSURdCgkJaWYgKG1lc3NhZ2UuZXJyb3IpIHsKCQkJcmV0dXJuIGNhbGxiYWNrRGF0YS5yZWplY3QobWVzc2FnZS5lcnJvcikKCQl9CgkJcmV0dXJuIGNhbGxiYWNrRGF0YS5yZXNvbHZlKG1lc3NhZ2UuZGF0YSkKCX0KCgkvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKCgkvKioqKioqKioqKioqKioqKioqKioqKioqKiogRXZlbnRzICoqKioqKioqKioqKioqKioqKioqKioqKioqLwoKCXZhciBldmVudExpc3RlbmVycyA9IHt9OwoKCS8vIFJlZ2lzdGVycyBldmVudCBsaXN0ZW5lcnMKCWZ1bmN0aW9uIG9uKGV2ZW50TmFtZSwgY2FsbGJhY2spIHsKCQlldmVudExpc3RlbmVyc1tldmVudE5hbWVdID0gZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSB8fCBbXTsKCQlldmVudExpc3RlbmVyc1tldmVudE5hbWVdLnB1c2goY2FsbGJhY2spOwoJfQoKCS8vIG5vdGlmeSBpbmZvcm1zIGZyb250ZW5kIGxpc3RlbmVycyB0aGF0IGFuIGV2ZW50IHdhcyBlbWl0dGVkIHdpdGggdGhlIGdpdmVuIGRhdGEKCWZ1bmN0aW9uIG5vdGlmeShldmVudE5hbWUsIGRhdGEpIHsKCQlpZiAoZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSkgewoJCQlldmVudExpc3RlbmVyc1tldmVudE5hbWVdLmZvckVhY2goZWxlbWVudCA9PiB7CgkJCQl2YXIgcGFyc2VkRGF0YSA9IFtdCgkJCQkvLyBQYXJzZSBkYXRhIGlmIHdlIGhhdmUgaXQKCQkJCWlmIChkYXRhKSB7CgkJCQkJdHJ5IHsKCQkJCQkJcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoZGF0YSk7CgkJCQkJfSBjYXRjaCAoZSkgewoJCQkJCQl3YWlscy5sb2cuZXJyb3IoIkludmFsaWQgSlNPTiBkYXRhIHNlbnQgdG8gbm90aWZ5LiBFdmVudCBuYW1lID0gIiArIGV2ZW50TmFtZSkKCQkJCQl9CgkJCQl9CgkJCQllbGVtZW50LmFwcGx5KG51bGwsIHBhcnNlZERhdGEpOwoJCQl9KTsKCQl9Cgl9CgoJLy8gZW1pdCBhbiBldmVudCB3aXRoIHRoZSBnaXZlbiBuYW1lIGFuZCBkYXRhCglmdW5jdGlvbiBlbWl0KGV2ZW50TmFtZSkgewoKCQkvLyBDYWxjdWxhdGUgdGhlIGRhdGEKCQl2YXIgZGF0YSA9IEpTT04uc3RyaW5naWZ5KFtdLnNsaWNlLmFwcGx5KGFyZ3VtZW50cykuc2xpY2UoMSkpOwoKCQkvLyBOb3RpZnkgYmFja2VuZAoJCW1lc3NhZ2UgPSB7CgkJCXR5cGU6ICJldmVudCIsCgkJCXBheWxvYWQ6IHsKCQkJCW5hbWU6IGV2ZW50TmFtZSwKCQkJCWRhdGE6IGRhdGEsCgkJCX0KCQl9CgkJZXh0ZXJuYWwuaW52b2tlKEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpKTsKCX0KCgkvLyBFdmVudHMgY2FsbHMKCXdpbmRvdy53YWlscy5ldmVudHMgPSB7IGVtaXQ6IGVtaXQsIG9uOiBvbiB9OwoKCS8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovCgoJLyoqKioqKioqKioqKioqKioqKioqKioqKiogTG9nZ2luZyAqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCgkvLyBTZW5kcyBhIGxvZyBtZXNzYWdlIHRvIHRoZSBiYWNrZW5kIHdpdGggdGhlIGdpdmVuCgkvLyBsZXZlbCArIG1lc3NhZ2UKCWZ1bmN0aW9uIHNlbmRMb2dNZXNzYWdlKGxldmVsLCBtZXNzYWdlKSB7CgoJCS8vIExvZyBNZXNzYWdlCgkJbWVzc2FnZSA9IHsKCQkJdHlwZTogImxvZyIsCgkJCXBheWxvYWQ6IHsKCQkJCWxldmVsOiBsZXZlbCwKCQkJCW1lc3NhZ2U6IG1lc3NhZ2UsCgkJCX0KCQl9CgkJZXh0ZXJuYWwuaW52b2tlKEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpKTsKCX0KCglmdW5jdGlvbiBsb2dEZWJ1ZyhtZXNzYWdlKSB7CgkJc2VuZExvZ01lc3NhZ2UoImRlYnVnIiwgbWVzc2FnZSk7Cgl9CglmdW5jdGlvbiBsb2dJbmZvKG1lc3NhZ2UpIHsKCQlzZW5kTG9nTWVzc2FnZSgiaW5mbyIsIG1lc3NhZ2UpOwoJfQoJZnVuY3Rpb24gbG9nV2FybmluZyhtZXNzYWdlKSB7CgkJc2VuZExvZ01lc3NhZ2UoIndhcm5pbmciLCBtZXNzYWdlKTsKCX0KCWZ1bmN0aW9uIGxvZ0Vycm9yKG1lc3NhZ2UpIHsKCQlzZW5kTG9nTWVzc2FnZSgiZXJyb3IiLCBtZXNzYWdlKTsKCX0KCWZ1bmN0aW9uIGxvZ0ZhdGFsKG1lc3NhZ2UpIHsKCQlzZW5kTG9nTWVzc2FnZSgiZmF0YWwiLCBtZXNzYWdlKTsKCX0KCgl3aW5kb3cud2FpbHMubG9nID0gewoJCWRlYnVnOiBsb2dEZWJ1ZywKCQlpbmZvOiBsb2dJbmZvLAoJCXdhcm5pbmc6IGxvZ1dhcm5pbmcsCgkJZXJyb3I6IGxvZ0Vycm9yLAoJCWZhdGFsOiBsb2dGYXRhbCwKCX07CgoJLyoqKioqKioqKioqKioqKioqKioqKioqKioqIEV4cG9ydHMgKioqKioqKioqKioqKioqKioqKioqKioqKi8KCgl3aW5kb3cud2FpbHMuXyA9IHsKCQluZXdCaW5kaW5nOiBuZXdCaW5kaW5nLAoJCWNhbGxiYWNrOiBjYWxsYmFjaywKCQlub3RpZnk6IG5vdGlmeSwKCQlzZW5kTG9nTWVzc2FnZTogc2VuZExvZ01lc3NhZ2UsCgkJY2FsbGJhY2tzOiBjYWxsYmFja3MsCgkJaW5qZWN0Q1NTOiBpbmplY3RDU1MsCgkJYWRkU2NyaXB0OiBhZGRTY3JpcHQsCgkJc2V0RG9jdW1lbnQ6IHNldERvY3VtZW50LAoJfQoKCS8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovCgoJLy8gTm90aWZ5IGJhY2tlbmQgdGhhdCB0aGUgcnVudGltZSBoYXMgZmluaXNoZWQgbG9hZGluZwoJd2luZG93LndhaWxzLmV2ZW50cy5lbWl0KCJ3YWlsczpsb2FkZWQiKTsKCn0pKCk=\"") + packr.PackJSONBytes("./assets/headless", "index.html", "\"PGh0bWw+Cgo8aGVhZD4KICA8dGl0bGU+V2FpbHMgSGVhZGxlc3M8L3RpdGxlPgogIDxzdHlsZT4KICAgIC53YWlscy1yZWNvbm5lY3Qtb3ZlcmxheSB7CiAgICAgIHBvc2l0aW9uOiBmaXhlZDsKICAgICAgdG9wOiAwOwogICAgICBsZWZ0OiAwOwogICAgICB3aWR0aDogMTAwJTsKICAgICAgaGVpZ2h0OiAxMDAlOwogICAgICBiYWNrZ3JvdW5kOiByZ2JhKDAsIDAsIDAsIDAuNik7CiAgICAgIGZvbnQtZmFtaWx5OiBzYW5zLXNlcmlmOwogICAgICBkaXNwbGF5OiBub25lOwogICAgICB6LWluZGV4OiA5OTk5OTk7CiAgICB9CgogICAgLndhaWxzLXJlY29ubmVjdC1vdmVybGF5LWNvbnRlbnQgewogICAgICBwYWRkaW5nOiAyMHB4IDMwcHg7CiAgICAgIHRleHQtYWxpZ246IGNlbnRlcjsKICAgICAgd2lkdGg6IDIwZW07CiAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTsKICAgICAgaGVpZ2h0OiAxN2VtOwogICAgICBib3JkZXItcmFkaXVzOiAxZW07CiAgICAgIG1hcmdpbjogNSUgYXV0byAwOwogICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB3aGl0ZTsKICAgICAgYm94LXNoYWRvdzogMXB4IDFweCAyMHB4IDNweDsKICAgICAgYmFja2dyb3VuZC1pbWFnZTogdXJsKCJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUM4QUFBQXVDQU1BQUFDUHBiQTdBQUFBcUZCTVZFVUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVCQVFBQUFBQUFBQUVCQVFBQUFBQUFBQUFBQUFFQkFRRUJBUURBd01CQVFFQUFBQUJBUUVBQUFBQUFBQUFBQUFCQVFFQUFBQUFBQUFDQWdJQ0FnSUJBUUVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQVFFQUFBQUNBZ0lBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFGQlFXS0NqNm9BQUFBTjNSU1RsTUFMaUlxRGhrR0JBc3dKalAwR3hQNk5SNFc5L3p0alJETWhXVTUwRzlnNWVIWHZiWjlYRUk5eFpUY3FabDJhbGRLbzU1UXdvQ3ZaVWd6aEFBQUFzOUpSRUZVU01lTmxlZVdxakFVaFUwQkNhSDNJdGl3OXpLVDkzK3pHMDJRSzFobS81SEYranpaSjZmUWU2Y3lYRStqZzlYN285d3h1eWxJSWY0VHYyVjMrYk9yRVhuZjhkd1EvS1FJR0ROMi9TKzRPbVZDVlhML1NjQm5maWJ4VVJxSUJ5UC9oT05FOHI4VCtiRE1sUTk4S1NsN1k4aHpqcFM4djFxdERoOHU1ZjhLUXBHcGZuUFBocUc4SmVvZ04zN0hxOWVhTjJ4UmhJd0FhR252d3M4RjFTaHhxSzVvYjJ0d1lpMUZBTUQ0clhzWXRuQy9KRWlSYmw0Y1VyQ1dobk1DTFJGZW1YZXpYYmI1OVFLNFdBU09zbTZuMlcxKzRDQlQySm10elE2ZnNyYkd1YlIvTkZiZDJnNVkxNzkrNXcvR0VIYUtzSGpZQ2V0N0NnclhVM3R4YXJOQzdZeE9WSnRJajQvRVJ6TWRaZnpjMzFocCs4Y0Q2ZUdJTGdhclpZOXVaMTJoQXMwM3ZmQkQ5QzE3MWdTNU9tejdPY3Z4QUxRSW40dThSUkJCQmNzaTlXVzJ3b085aXBMZ2Z6cFlsZ2dnM1pSZFJPVUM4S1Q3UUxxcTNXOUtCNUJiZEZWZzQ5MjlrZHdwNitxYVpuTUNDTkJkaitOeU4xVzg4NVJ5L0FMM0Q0QVFic1ZWNG5vQ2lNL0M4M2t5WXE4MFhsREFZUXRyYWxPaUR6b1JBSGxvdFdsOHEydGp2WWxPZ2NnMUE4akVBcFphK0MwNlRCZEF6MlF2MHd1MTFJL3paT3lKUTZFd0dlejJQMmI4UElRcjFod3duQVpzQXh3QTRVQVlPeVhVeE0veHA2dEhBbjRHVW1QR005UjI4b1Z4Z0MwZS96UUpKSTZEeWh5WjFyN3V6UlFocGNXN3g3dlRhV1N6S1NHNmFlcDc3a3JvVEVsM1U4MXVTVmFVVHRnRUlOZkM4ZXB4K1E0RjlTcHBsSEc4NEVrNm00UkFxOS9UTGtPQnJ4eWV1ZGRaaEh2R0lwMVhYZkZ5M1ozdnR3TmJsS0dpRG4rSis5MnZ3d0FCSGdoajdIbnpsUzFINWtCNDlBWnZkR0NGZ2lCUHE2OXFmWFByM3krK3lpbEYwT040UjhlUjdzcEFzTHBaOTVOcUFXNXRhYjFjNHZrWm02YWxlYWpjaE13WVRkSUxRUVR3RTJPVjQxMVpNOVd6dERqUHFsMTJjYUJpNmdEcFVLbURkNFUxWE5kUXhaNExJWFE1L1RyNFA3STl0WWNGckRLM0FBQUFBRWxGVGtTdVFtQ0MiKTsKICAgICAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsKICAgICAgYmFja2dyb3VuZC1wb3NpdGlvbjogY2VudGVyOwogICAgfQoKICAgIC53YWlscy1yZWNvbm5lY3Qtb3ZlcmxheS10aXRsZSB7CiAgICAgIGZvbnQtc2l6ZTogMmVtOwogICAgfQoKICAgIC53YWlscy1yZWNvbm5lY3Qtb3ZlcmxheS1tZXNzYWdlIHsKICAgICAgZm9udC1zaXplOiAxLjNlbTsKICAgIH0KCiAgICAvKiBodHRwczovL2NvZGVwZW4uaW8vRWFzdGluZ0FuZE5vcnRoaW5nL3Blbi9hTldyWnogLSBDaGVlcnMgTWFyayEgKi8KCiAgICAud2FpbHMtcmVjb25uZWN0LW92ZXJsYXktbG9hZGluZ3NwaW5uZXIgewogICAgICBwb2ludGVyLWV2ZW50czogbm9uZTsKICAgICAgd2lkdGg6IDIuNWVtOwogICAgICBoZWlnaHQ6IDIuNWVtOwogICAgICBib3JkZXI6IDAuNGVtIHNvbGlkIHRyYW5zcGFyZW50OwogICAgICBib3JkZXItY29sb3I6ICNlZWU7CiAgICAgIGJvcmRlci10b3AtY29sb3I6ICMzRTY3RUM7CiAgICAgIGJvcmRlci1yYWRpdXM6IDUwJTsKICAgICAgYW5pbWF0aW9uOiBsb2FkaW5nc3BpbiAxcyBsaW5lYXIgaW5maW5pdGU7CiAgICAgIG1hcmdpbjogYXV0bzsKICAgICAgcGFkZGluZzogMi41ZW07CiAgICB9CgogICAgQGtleWZyYW1lcyBsb2FkaW5nc3BpbiB7CiAgICAgIDEwMCUgewogICAgICAgIHRyYW5zZm9ybTogcm90YXRlKDM2MGRlZykKICAgICAgfQogICAgfQogIDwvc3R5bGU+CjwvaGVhZD4KCjxib2R5PgogIDxkaXYgY2xhc3M9IndhaWxzLXJlY29ubmVjdC1vdmVybGF5Ij4KICAgIDxkaXYgY2xhc3M9IndhaWxzLXJlY29ubmVjdC1vdmVybGF5LWNvbnRlbnQiPgogICAgICA8ZGl2IGNsYXNzPSJ3YWlscy1yZWNvbm5lY3Qtb3ZlcmxheS10aXRsZSI+RGlzY29ubmVjdGVkPC9kaXY+PGJyPgogICAgICA8ZGl2IGNsYXNzPSJ3YWlscy1yZWNvbm5lY3Qtb3ZlcmxheS1sb2FkaW5nc3Bpbm5lciI+PC9kaXY+PGJyPgogICAgICA8ZGl2IGNsYXNzPSJ3YWlscy1yZWNvbm5lY3Qtb3ZlcmxheS1tZXNzYWdlIj5XYWl0aW5nIGZvciBiYWNrZW5kPC9kaXY+CiAgICA8L2Rpdj4KICA8L2Rpdj4KCiAgPGRpdiBpZD0iYXBwIj48L2Rpdj4KCiAgPHNjcmlwdCBpZD0id2FpbHMtaGVhZGxlc3MtcnVudGltZSI+CiAgICAoZnVuY3Rpb24gKCkgewoKICAgICAgdmFyIHdlYnNvY2tldCA9IG51bGw7CiAgICAgIHZhciBjb25uZWN0VGltZXIgPSBudWxsOwogICAgICB2YXIgcmVjb25uZWN0T3ZlcmxheSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoIi53YWlscy1yZWNvbm5lY3Qtb3ZlcmxheSIpOwogICAgICB2YXIgY29ubmVjdGlvblN0YXRlID0gImRpc2Nvbm5lY3RlZCI7CgogICAgICBmdW5jdGlvbiBzaG93UmVjb25uZWN0T3ZlcmxheSgpIHsKICAgICAgICByZWNvbm5lY3RPdmVybGF5LnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snOwogICAgICB9CgogICAgICBmdW5jdGlvbiBoaWRlUmVjb25uZWN0T3ZlcmxheSgpIHsKICAgICAgICByZWNvbm5lY3RPdmVybGF5LnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7CiAgICAgIH0KCiAgICAgIHdpbmRvdy5leHRlcm5hbCA9IHsKICAgICAgICBpbnZva2U6IGZ1bmN0aW9uIChtc2cpIHsKICAgICAgICAgIHdlYnNvY2tldC5zZW5kKG1zZyk7CiAgICAgICAgfQogICAgICB9OwoKICAgICAgZnVuY3Rpb24gYWRkU2NyaXB0KHNjcmlwdCwgaWQpIHsKICAgICAgICB2YXIgcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInNjcmlwdCIpCiAgICAgICAgaWYgKGlkKSB7CiAgICAgICAgICBzLmlkID0gaWQ7CiAgICAgICAgfQogICAgICAgIHMudGV4dENvbnRlbnQgPSBzY3JpcHQ7CiAgICAgICAgZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChzKQogICAgICB9CgogICAgICBmdW5jdGlvbiBoYW5kbGVDb25uZWN0KCkgewogICAgICAgIGNvbnNvbGUubG9nKCJbV2FpbHNdIENvbm5lY3RlZCB0byBiYWNrZW5kIik7CiAgICAgICAgYWRkS2V5TGlzdGVuZXIoKTsKICAgICAgICBoaWRlUmVjb25uZWN0T3ZlcmxheSgpOwogICAgICAgIGNsZWFySW50ZXJ2YWwoY29ubmVjdFRpbWVyKTsKICAgICAgICB3ZWJzb2NrZXQub25jbG9zZSA9IGhhbmRsZURpc2Nvbm5lY3Q7CiAgICAgICAgd2Vic29ja2V0Lm9ubWVzc2FnZSA9IGhhbmRsZU1lc3NhZ2U7CiAgICAgICAgY29ubmVjdGlvblN0YXRlID0gImNvbm5lY3RlZCI7CiAgICAgICAgLy8gd2Vic29ja2V0Lm9uZXJyb3IgPSBmdW5jdGlvbiAoKSB7IH0KICAgICAgfQoKICAgICAgZnVuY3Rpb24gaGFuZGxlRGlzY29ubmVjdCgpIHsKICAgICAgICBjb25zb2xlLmxvZygiW1dhaWxzXSBEaXNjb25uZWN0ZWQgZnJvbSBiYWNrZW5kIik7CiAgICAgICAgd2Vic29ja2V0ID0gbnVsbDsKICAgICAgICByZW1vdmVLZXlMaXN0ZW5lcigpOwogICAgICAgIGNvbm5lY3Rpb25TdGF0ZSA9ICJkaXNjb25uZWN0ZWQiOwogICAgICAgIHNob3dSZWNvbm5lY3RPdmVybGF5KCk7CiAgICAgICAgY29ubmVjdCgpOwogICAgICB9CgogICAgICBmdW5jdGlvbiBjb25uZWN0KCkgewogICAgICAgIGNvbm5lY3RUaW1lciA9IHNldEludGVydmFsKGZ1bmN0aW9uICgpIHsKICAgICAgICAgIGlmICh3ZWJzb2NrZXQgPT0gbnVsbCkgewogICAgICAgICAgICB3ZWJzb2NrZXQgPSBuZXcgV2ViU29ja2V0KCJ3czovL2xvY2FsaG9zdDozNDExNS93cyIpCiAgICAgICAgICAgIHdlYnNvY2tldC5vbm9wZW4gPSBoYW5kbGVDb25uZWN0OwogICAgICAgICAgICB3ZWJzb2NrZXQub25lcnJvciA9IGZ1bmN0aW9uIChlKSB7CiAgICAgICAgICAgICAgZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTsKICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpOwogICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTsKICAgICAgICAgICAgICB3ZWJzb2NrZXQgPSBudWxsOwogICAgICAgICAgICAgIHJldHVybiBmYWxzZQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfSwgMzAwKTsKICAgICAgfQoKICAgICAgZnVuY3Rpb24gaGFuZGxlTWVzc2FnZShlKSB7CiAgICAgICAgYWRkU2NyaXB0KGUuZGF0YSk7CiAgICAgIH0KCiAgICAgIC8vIEtleSBsaXN0ZW5lcgogICAgICB2YXIgZGVsdGEgPSAzMDA7CiAgICAgIHZhciBsYXN0S2V5cHJlc3NUaW1lID0gMDsKICAgICAgZnVuY3Rpb24gS2V5SGFuZGxlcihldmVudCkgewogICAgICAgIGlmIChldmVudC5rZXkgPT09ICJgIikgewogICAgICAgICAgdmFyIHRoaXNLZXlwcmVzc1RpbWUgPSBuZXcgRGF0ZSgpOwogICAgICAgICAgaWYgKHRoaXNLZXlwcmVzc1RpbWUgLSBsYXN0S2V5cHJlc3NUaW1lIDw9IGRlbHRhKSB7CiAgICAgICAgICAgIGNvbnNvbGUubG9nKCJEb3VibGUgdGFwISIpCiAgICAgICAgICAgIC8vIG9wdGlvbmFsIC0gaWYgd2UnZCByYXRoZXIgbm90IGRldGVjdCBhIHRyaXBsZS1wcmVzcwogICAgICAgICAgICAvLyBhcyBhIHNlY29uZCBkb3VibGUtcHJlc3MsIHJlc2V0IHRoZSB0aW1lc3RhbXAKICAgICAgICAgICAgdGhpc0tleXByZXNzVGltZSA9IDA7CiAgICAgICAgICB9CiAgICAgICAgICBsYXN0S2V5cHJlc3NUaW1lID0gdGhpc0tleXByZXNzVGltZTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIGZ1bmN0aW9uIGFkZEtleUxpc3RlbmVyKCkgewogICAgICAgIGRvY3VtZW50LmJvZHkuYWRkRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIEtleUhhbmRsZXIpOwogICAgICB9CgogICAgICBmdW5jdGlvbiByZW1vdmVLZXlMaXN0ZW5lcigpIHsKICAgICAgICBkb2N1bWVudC5ib2R5LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCBLZXlIYW5kbGVyKTsKICAgICAgfQoKICAgICAgY29ubmVjdCgpOwoKCiAgICB9KCkpOwoKICA8L3NjcmlwdD4KCjwvYm9keT4KCjwvaHRtbD4=\"") +} diff --git a/app.go b/app.go new file mode 100644 index 000000000..894c9f0d4 --- /dev/null +++ b/app.go @@ -0,0 +1,142 @@ +package wails + +import ( + "github.com/wailsapp/wails/cmd" + "github.com/wailsapp/wails/cmd/frameworks" +) + +// -------------------------------- Compile time Flags ------------------------------ + +// ReleaseMode indicates if we are in Release Mode +var ReleaseMode = false + +// ---------------------------------------------------------------------------------- + +// App defines the main application struct +type App struct { + config *AppConfig // The Application configuration object + cli *cmd.Cli // In debug mode, we have a cli + renderer Renderer // The renderer is what we will render the app to + logLevel string // The log level of the app + headless bool // Indicates if the app should be started in headless mode + ipc *ipcManager // Handles the IPC calls + log *CustomLogger // Logger + bindingManager *bindingManager // Handles binding of Go code to renderer + eventManager *eventManager // Handles all the events + runtime *Runtime // The runtime object for registered structs + + // This is a list of all the JS/CSS that needs injecting + // It will get injected in order + jsCache []string + cssCache []string +} + +// CreateApp creates the application window with the given configuration +// If none given, the defaults are used +func CreateApp(optionalConfig ...*AppConfig) *App { + var userConfig *AppConfig + if len(optionalConfig) > 0 { + userConfig = optionalConfig[0] + } + + result := &App{ + logLevel: "debug", + renderer: &webViewRenderer{}, + ipc: newIPCManager(), + bindingManager: newBindingManager(), + eventManager: newEventManager(), + log: newCustomLogger("App"), + } + + appconfig, err := newAppConfig(userConfig) + if err != nil { + result.log.Fatalf("Cannot use custom HTML: %s", err.Error()) + } + result.config = appconfig + + // Set up the CLI if not in release mode + if !ReleaseMode { + result.cli = result.setupCli() + } + + // Disable Inspector in release mode + if ReleaseMode { + result.config.DisableInspector = true + } + + return result +} + +// Run the app +func (a *App) Run() { + a.cli.Run() +} + +func (a *App) start() error { + + // Set the log level + setLogLevel(a.logLevel) + + // Log starup + a.log.Info("Starting") + + // Check if we are to run in headless mode + if a.headless { + a.renderer = &Headless{} + } + + // Initialise the renderer + err := a.renderer.Initialise(a.config, a.ipc, a.eventManager) + if err != nil { + return err + } + + // Start event manager and give it our renderer + a.eventManager.start(a.renderer) + + // Start the IPC Manager and give it the event manager and binding manager + a.ipc.start(a.eventManager, a.bindingManager) + + // Create the runtime + a.runtime = newRuntime(a.eventManager, a.renderer) + + // Start binding manager and give it our renderer + err = a.bindingManager.start(a.renderer, a.runtime) + if err != nil { + return err + } + + // Inject framework, if specified + if frameworks.FrameworkToUse != nil { + a.renderer.InjectFramework(frameworks.FrameworkToUse.JS, frameworks.FrameworkToUse.CSS) + } + + // Inject CSS + a.renderer.AddCSSList(a.cssCache) + + // Inject JS + a.renderer.AddJSList(a.jsCache) + + // Run the renderer + a.renderer.Run() + + return nil +} + +// Bind allows the user to bind the given object +// with the application +func (a *App) Bind(object interface{}) { + a.bindingManager.bind(object) +} + +// AddJS adds a piece of Javascript to a cache that +// gets injected at runtime +func (a *App) AddJS(js string) { + a.jsCache = append(a.jsCache, js) +} + +// AddCSS adds a CSS string to a cache that +// gets injected at runtime +func (a *App) AddCSS(js string) { + a.cssCache = append(a.cssCache, js) +} diff --git a/app_cli.go b/app_cli.go new file mode 100644 index 000000000..fb1792769 --- /dev/null +++ b/app_cli.go @@ -0,0 +1,38 @@ +package wails + +import ( + "fmt" + + "github.com/wailsapp/wails/cmd" +) + +func (app *App) setupCli() *cmd.Cli { + + // var apiFilename string + + result := cmd.NewCli(app.config.Title, "Debug build") + + // Gen API + // result.Command("genapi", "Generate JS stubs for the registered Go plugins"). + // StringFlag("o", "Output filename", &apiFilename). + // Action(func() error { + // app.renderer = N + // }) + + result. + StringFlag("loglevel", "Sets the log level [info|debug|error|panic|fatal]. Default debug", &app.logLevel). + BoolFlag("headless", "Runs the app in headless mode", &app.headless). + Action(app.start) + + // Banner + result.PreRun(func(cli *cmd.Cli) error { + log := cmd.NewLogger() + log.PrintBanner() + fmt.Println() + result.PrintHelp() + log.YellowUnderline(app.config.Title + " - Debug Build") + return nil + }) + + return result +} diff --git a/app_config.go b/app_config.go new file mode 100644 index 000000000..a1cd3156a --- /dev/null +++ b/app_config.go @@ -0,0 +1,99 @@ +package wails + +import ( + "strings" + + "github.com/dchest/htmlmin" + "github.com/gobuffalo/packr" +) + +var assets = packr.NewBox("./assets/default") + +// AppConfig is the configuration structure used when creating a Wails App object +type AppConfig struct { + Width, Height int + Title string + defaultHTML string + HTML string + JS string + CSS string + Colour string + Resizable bool + DisableInspector bool + isHTMLFragment bool +} + +func (a *AppConfig) merge(in *AppConfig) error { + if in.CSS != "" { + a.CSS = in.CSS + } + if in.Title != "" { + a.Title = in.Title + } + if in.HTML != "" { + minified, err := htmlmin.Minify([]byte(in.HTML), &htmlmin.Options{ + MinifyScripts: true, + }) + if err != nil { + return err + } + inlineHTML := string(minified) + inlineHTML = strings.Replace(inlineHTML, "'", "\\'", -1) + inlineHTML = strings.Replace(inlineHTML, "\n", " ", -1) + a.HTML = strings.TrimSpace(inlineHTML) + + // Deduce whether this is a full html page or a fragment + // The document is determined to be a fragment if an HMTL + // tag exists and is located before the first div tag + HTMLTagIndex := strings.Index(a.HTML, " 0 { + b.inputs = make([]reflect.Type, inputParamCount) + // We start at 1 as the first param is the struct + for index := 0; index < inputParamCount; index++ { + param := functionType.In(index) + name := param.Name() + kind := param.Kind() + b.inputs[index] = param + typ := param + index := index + b.log.DebugFields("Input param", Fields{ + "index": index, + "name": name, + "kind": kind, + "typ": typ, + }) + } + } + + // Process return/output declarations + returnParamsCount := functionType.NumOut() + // Guard against bad number of return types + switch returnParamsCount { + case 0: + case 1: + // Check if it's an error type + param := functionType.Out(0) + paramName := param.Name() + if paramName == "error" { + b.hasErrorReturnType = true + } + // Save return type + b.returnTypes = append(b.returnTypes, param) + case 2: + // Check the second return type is an error + secondParam := functionType.Out(1) + secondParamName := secondParam.Name() + if secondParamName != "error" { + return fmt.Errorf("last return type of method '%s' must be an error (got %s)", b.fullName, secondParamName) + } + + // Check the second return type is an error + firstParam := functionType.Out(0) + firstParamName := firstParam.Name() + if firstParamName == "error" { + return fmt.Errorf("first return type of method '%s' must not be an error", b.fullName) + } + b.hasErrorReturnType = true + + // Save return types + b.returnTypes = append(b.returnTypes, firstParam) + b.returnTypes = append(b.returnTypes, secondParam) + + default: + return fmt.Errorf("cannot register method '%s' with %d return parameters. Please use up to 2", b.fullName, returnParamsCount) + } + + return nil +} + +// call the method with the given data +func (b *boundFunction) call(data string) ([]reflect.Value, error) { + + // The data will be an array of values so we will decode the + // input data into + var jsArgs []interface{} + d := json.NewDecoder(bytes.NewBufferString(data)) + // d.UseNumber() + err := d.Decode(&jsArgs) + if err != nil { + return nil, fmt.Errorf("Invalid data passed to method call: %s", err.Error()) + } + + // Check correct number of inputs + if len(jsArgs) != len(b.inputs) { + return nil, fmt.Errorf("Invalid number of parameters given to %s. Expected %d but got %d", b.fullName, len(b.inputs), len(jsArgs)) + } + + // Set up call + args := make([]reflect.Value, len(b.inputs)) + for index := 0; index < len(b.inputs); index++ { + + // Set the input values + value, err := b.setInputValue(index, b.inputs[index], jsArgs[index]) + if err != nil { + return nil, err + } + args[index] = value + } + b.log.Infof("Unmarshalled Args: %+v\n", jsArgs) + b.log.Infof("Converted Args: %+v\n", args) + results := b.function.Call(args) + + b.log.Debugf("results = %+v", results) + return results, nil +} + +// Attempts to set the method input for parameter with the given value +func (b *boundFunction) setInputValue(index int, typ reflect.Type, val interface{}) (result reflect.Value, err error) { + + // Catch type conversion panics thrown by convert + defer func() { + if r := recover(); r != nil { + // Modify error + err = fmt.Errorf("%s for parameter %d of function %s", r.(string)[23:], index+1, b.fullName) + } + }() + + // Do the conversion + result = reflect.ValueOf(val).Convert(typ) + + return result, err +} diff --git a/binding_manager.go b/binding_manager.go new file mode 100644 index 000000000..6a9411b63 --- /dev/null +++ b/binding_manager.go @@ -0,0 +1,267 @@ +package wails + +import ( + "fmt" + "reflect" + "unicode" +) + +/** + +binding: + Name() // Full name (package+name) + Call(params) + +**/ + +type bindingManager struct { + methods map[string]*boundMethod + functions map[string]*boundFunction + initMethods []*boundMethod + log *CustomLogger + renderer Renderer + runtime *Runtime // The runtime object to pass to bound structs + objectsToBind []interface{} + bindPackageNames bool // Package name should be considered when binding +} + +func newBindingManager() *bindingManager { + result := &bindingManager{ + methods: make(map[string]*boundMethod), + functions: make(map[string]*boundFunction), + log: newCustomLogger("Bind"), + } + return result +} + +// Sets flag to indicate package names should be considered when binding +func (b *bindingManager) BindPackageNames() { + b.bindPackageNames = true +} + +func (b *bindingManager) start(renderer Renderer, runtime *Runtime) error { + b.log.Info("Starting") + b.renderer = renderer + b.runtime = runtime + err := b.initialise() + if err != nil { + b.log.Errorf("Binding error: %s", err.Error()) + return err + } + err = b.callWailsInitMethods() + return err +} + +func (b *bindingManager) initialise() error { + + var err error + // var binding *boundMethod + + b.log.Info("Binding Go Functions/Methods") + + // Create bindings for objects + for _, object := range b.objectsToBind { + + // Safeguard against nils + if object == nil { + return fmt.Errorf("attempted to bind nil object") + } + + // Determine kind of object + objectType := reflect.TypeOf(object) + objectKind := objectType.Kind() + + switch objectKind { + case reflect.Ptr: + err = b.bindMethod(object) + case reflect.Func: + // spew.Dump(result.objectType.String()) + err = b.bindFunction(object) + default: + err = fmt.Errorf("cannot bind object of type '%s'", objectKind.String()) + } + + // Return error if set + if err != nil { + return err + } + } + return nil +} + +// bind the given struct method +func (b *bindingManager) bindMethod(object interface{}) error { + + objectType := reflect.TypeOf(object) + baseName := objectType.String() + + // Strip pointer if there + if baseName[0] == '*' { + baseName = baseName[1:] + } + + b.log.Debugf("Processing struct: %s", baseName) + + // Iterate over method definitions + for i := 0; i < objectType.NumMethod(); i++ { + + // Get method definition + methodDef := objectType.Method(i) + methodName := methodDef.Name + fullMethodName := baseName + "." + methodName + method := reflect.ValueOf(object).MethodByName(methodName) + + // Skip unexported methods + if !unicode.IsUpper([]rune(methodName)[0]) { + continue + } + + // Create a new boundMethod + newMethod, err := newBoundMethod(methodName, fullMethodName, method, objectType) + if err != nil { + return err + } + + // Check if it's a wails init function + if newMethod.isWailsInit { + b.log.Debugf("Detected WailsInit function: %s", fullMethodName) + b.initMethods = append(b.initMethods, newMethod) + } else { + // Save boundMethod + b.log.Infof("Bound Method: %s()", fullMethodName) + b.methods[fullMethodName] = newMethod + + // Inform renderer of new binding + b.renderer.NewBinding(fullMethodName) + } + } + + return nil +} + +// bind the given function object +func (b *bindingManager) bindFunction(object interface{}) error { + + newFunction, err := newBoundFunction(object) + if err != nil { + return err + } + + // Save method + b.log.Infof("Bound Function: %s()", newFunction.fullName) + b.functions[newFunction.fullName] = newFunction + + // Register with Renderer + b.renderer.NewBinding(newFunction.fullName) + + return nil +} + +// Save the given object to be bound at start time +func (b *bindingManager) bind(object interface{}) { + // Store binding + b.objectsToBind = append(b.objectsToBind, object) +} + +// process an incoming call request +func (b *bindingManager) processCall(callData *callData) (interface{}, error) { + b.log.Debugf("Wanting to call %s", callData.BindingName) + + // Determine if this is function call or method call by the number of + // dots in the binding name + dotCount := 0 + for _, character := range callData.BindingName { + if character == '.' { + dotCount++ + } + } + + // Return values + var result []reflect.Value + var err error + + // We need to catch reflect related panics and return + // a decent error message + // TODO: DEBUG THIS! + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("%s", r.(string)) + } + }() + + switch dotCount { + case 1: + function := b.functions[callData.BindingName] + if function == nil { + return nil, fmt.Errorf("Invalid function name '%s'", callData.BindingName) + } + result, err = function.call(callData.Data) + if err != nil { + return nil, err + } + + // Do we have an error return type? + if function.hasErrorReturnType { + // We do - last result is an error type + // Check if the last result was nil + b.log.Debugf("# of return types: %d", len(function.returnTypes)) + b.log.Debugf("# of results: %d", len(result)) + errorResult := result[len(function.returnTypes)-1] + if !errorResult.IsNil() { + // It wasn't - we have an error + return nil, errorResult.Interface().(error) + } + } + return result[0].Interface(), nil + case 2: + // do we have this method? + method := b.methods[callData.BindingName] + if method == nil { + return nil, fmt.Errorf("Invalid method name '%s'", callData.BindingName) + } + result, err = method.call(callData.Data) + if err != nil { + return nil, err + } + + // Do we have an error return type? + if method.hasErrorReturnType { + // We do - last result is an error type + // Check if the last result was nil + b.log.Debugf("# of return types: %d", len(method.returnTypes)) + b.log.Debugf("# of results: %d", len(result)) + errorResult := result[len(method.returnTypes)-1] + if !errorResult.IsNil() { + // It wasn't - we have an error + return nil, errorResult.Interface().(error) + } + } + if result != nil { + return result[0].Interface(), nil + } + return nil, nil + + default: + return nil, fmt.Errorf("Invalid binding name '%s'", callData.BindingName) + } +} + +// callWailsInitMethods calls all of the WailsInit methods that were +// registered with the runtime object +func (b *bindingManager) callWailsInitMethods() error { + // Create reflect value for runtime object + runtimeValue := reflect.ValueOf(b.runtime) + params := []reflect.Value{runtimeValue} + + // Iterate initMethods + for _, initMethod := range b.initMethods { + // Call + result := initMethod.method.Call(params) + // Check errors + err := result[0].Interface() + if err != nil { + return err.(error) + } + } + return nil +} diff --git a/binding_method.go b/binding_method.go new file mode 100644 index 000000000..30ada36d8 --- /dev/null +++ b/binding_method.go @@ -0,0 +1,211 @@ +package wails + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" +) + +type boundMethod struct { + Name string + fullName string + method reflect.Value + inputs []reflect.Type + returnTypes []reflect.Type + log *CustomLogger + hasErrorReturnType bool // Indicates if there is an error return type + isWailsInit bool +} + +// Creates a new bound method based on the given method + type +func newBoundMethod(name string, fullName string, method reflect.Value, objectType reflect.Type) (*boundMethod, error) { + result := &boundMethod{ + Name: name, + method: method, + fullName: fullName, + } + + // Setup logger + result.log = newCustomLogger(result.fullName) + + // Check if Parameters are valid + err := result.processParameters() + + // Are we a WailsInit method? + if result.Name == "WailsInit" { + err = result.processWailsInit() + } + + return result, err +} + +func (b *boundMethod) processParameters() error { + + // Param processing + methodType := b.method.Type() + + // Input parameters + inputParamCount := methodType.NumIn() + if inputParamCount > 0 { + b.inputs = make([]reflect.Type, inputParamCount) + // We start at 1 as the first param is the struct + for index := 0; index < inputParamCount; index++ { + param := methodType.In(index) + name := param.Name() + kind := param.Kind() + b.inputs[index] = param + typ := param + index := index + b.log.DebugFields("Input param", Fields{ + "index": index, + "name": name, + "kind": kind, + "typ": typ, + }) + } + } + + // Process return/output declarations + returnParamsCount := methodType.NumOut() + // Guard against bad number of return types + switch returnParamsCount { + case 0: + case 1: + // Check if it's an error type + param := methodType.Out(0) + paramName := param.Name() + if paramName == "error" { + b.hasErrorReturnType = true + } + // Save return type + b.returnTypes = append(b.returnTypes, param) + case 2: + // Check the second return type is an error + secondParam := methodType.Out(1) + secondParamName := secondParam.Name() + if secondParamName != "error" { + return fmt.Errorf("last return type of method '%s' must be an error (got %s)", b.Name, secondParamName) + } + + // Check the second return type is an error + firstParam := methodType.Out(0) + firstParamName := firstParam.Name() + if firstParamName == "error" { + return fmt.Errorf("first return type of method '%s' must not be an error", b.Name) + } + b.hasErrorReturnType = true + + // Save return types + b.returnTypes = append(b.returnTypes, firstParam) + b.returnTypes = append(b.returnTypes, secondParam) + + default: + return fmt.Errorf("cannot register method '%s' with %d return parameters. Please use up to 2", b.Name, returnParamsCount) + } + + return nil +} + +// call the method with the given data +func (b *boundMethod) call(data string) ([]reflect.Value, error) { + + // The data will be an array of values so we will decode the + // input data into + var jsArgs []interface{} + d := json.NewDecoder(bytes.NewBufferString(data)) + // d.UseNumber() + err := d.Decode(&jsArgs) + if err != nil { + return nil, fmt.Errorf("Invalid data passed to method call: %s", err.Error()) + } + + // Check correct number of inputs + if len(jsArgs) != len(b.inputs) { + return nil, fmt.Errorf("Invalid number of parameters given to %s. Expected %d but got %d", b.fullName, len(b.inputs), len(jsArgs)) + } + + // Set up call + args := make([]reflect.Value, len(b.inputs)) + for index := 0; index < len(b.inputs); index++ { + + // Set the input values + value, err := b.setInputValue(index, b.inputs[index], jsArgs[index]) + if err != nil { + return nil, err + } + args[index] = value + } + b.log.Infof("Unmarshalled Args: %+v\n", jsArgs) + b.log.Infof("Converted Args: %+v\n", args) + results := b.method.Call(args) + + b.log.Debugf("results = %+v", results) + return results, nil +} + +// Attempts to set the method input for parameter with the given value +func (b *boundMethod) setInputValue(index int, typ reflect.Type, val interface{}) (result reflect.Value, err error) { + + // Catch type conversion panics thrown by convert + defer func() { + if r := recover(); r != nil { + // Modify error + fmt.Printf("Recovery message: %+v\n", r) + err = fmt.Errorf("%s for parameter %d of method %s", r.(string)[23:], index+1, b.fullName) + } + }() + + // Do the conversion + // Handle nil values + if val == nil { + switch typ.Kind() { + case reflect.Chan, + reflect.Func, + reflect.Interface, + reflect.Map, + reflect.Ptr, + reflect.Slice: + logger.Debug("Converting nil to type") + result = reflect.ValueOf(val).Convert(typ) + default: + logger.Debug("Cannot convert nil to type, returning error") + return reflect.Zero(typ), fmt.Errorf("Unable to use null value for parameter %d of method %s", index+1, b.fullName) + } + } else { + result = reflect.ValueOf(val).Convert(typ) + } + + return result, err +} + +func (b *boundMethod) processWailsInit() error { + // We must have only 1 input, it must be *wails.Runtime + if len(b.inputs) != 1 { + return fmt.Errorf("Invalid WailsInit() definition. Expected 1 input, but got %d", len(b.inputs)) + } + + // It must be *wails.Runtime + inputName := b.inputs[0].String() + b.log.Debugf("WailsInit input type: %s", inputName) + if inputName != "*wails.Runtime" { + return fmt.Errorf("Invalid WailsInit() definition. Expected input to be wails.Runtime, but got %s", inputName) + } + + // We must have only 1 output, it must be error + if len(b.returnTypes) != 1 { + return fmt.Errorf("Invalid WailsInit() definition. Expected 1 return type, but got %d", len(b.returnTypes)) + } + + // It must be *wails.Runtime + outputName := b.returnTypes[0].String() + b.log.Debugf("WailsInit output type: %s", outputName) + if outputName != "error" { + return fmt.Errorf("Invalid WailsInit() definition. Expected input to be error, but got %s", outputName) + } + + // We are indeed a wails Init method + b.isWailsInit = true + + return nil +} diff --git a/cmd/bundle.go b/cmd/bundle.go new file mode 100644 index 000000000..dd82add3c --- /dev/null +++ b/cmd/bundle.go @@ -0,0 +1,193 @@ +package cmd + +import ( + "bytes" + "fmt" + "image" + "io/ioutil" + "os" + "path" + "path/filepath" + "runtime" + "strings" + "text/template" + "time" + + "github.com/jackmordaunt/icns" +) + +// BundleHelper helps with the 'wails bundle' command +type BundleHelper struct { + fs *FSHelper + log *Logger + system *SystemHelper +} + +// NewBundleHelper creates a new BundleHelper! +func NewBundleHelper() *BundleHelper { + return &BundleHelper{ + fs: NewFSHelper(), + log: NewLogger(), + system: NewSystemHelper(), + } +} + +// var assetsBox packr.Box + +type plistData struct { + Title string + Exe string + BundleID string + Version string + Author string + Date string +} + +func newPlistData(title, exe, bundleID, version, author string) *plistData { + now := time.Now().Format(time.RFC822) + return &plistData{ + Title: title, + Exe: exe, + Version: version, + BundleID: bundleID, + Author: author, + Date: now, + } +} + +func defaultString(val string, defaultVal string) string { + if val != "" { + return val + } + return defaultVal +} + +func (b *BundleHelper) getBundleFileBaseDir() string { + return filepath.Join(b.system.homeDir, "go", "src", "github.com", "wailsapp", "wails", "cmd", "bundle", runtime.GOOS) +} + +// Bundle the application into a platform specific package +func (b *BundleHelper) Bundle(po *ProjectOptions) error { + // Check we have the exe + if !b.fs.FileExists(po.BinaryName) { + return fmt.Errorf("cannot bundle non-existant binary file '%s'. Please build with 'wails build' first", po.BinaryName) + } + switch runtime.GOOS { + case "darwin": + return b.bundleOSX(po) + default: + return fmt.Errorf("platform '%s' not supported for bundling yet", runtime.GOOS) + } +} + +// Bundle the application +func (b *BundleHelper) bundleOSX(po *ProjectOptions) error { + + system := NewSystemHelper() + config, err := system.LoadConfig() + if err != nil { + return err + } + + name := defaultString(po.Name, "WailsTest") + exe := defaultString(po.BinaryName, name) + version := defaultString(po.Version, "0.1.0") + author := defaultString(config.Name, "Anonymous") + bundleID := strings.Join([]string{"wails", name, version}, ".") + plistData := newPlistData(name, exe, bundleID, version, author) + appname := po.Name + ".app" + + // Check binary exists + source := path.Join(b.fs.Cwd(), exe) + if !b.fs.FileExists(source) { + // We need to build! + return fmt.Errorf("Target '%s' not available. Has it been compiled yet?", exe) + } + + // REmove the existing bundle + os.RemoveAll(appname) + + exeDir := path.Join(b.fs.Cwd(), appname, "/Contents/MacOS") + b.fs.MkDirs(exeDir, 0755) + resourceDir := path.Join(b.fs.Cwd(), appname, "/Contents/Resources") + b.fs.MkDirs(resourceDir, 0755) + tmpl := template.New("infoPlist") + plistFile := filepath.Join(b.getBundleFileBaseDir(), "info.plist") + infoPlist, err := ioutil.ReadFile(plistFile) + if err != nil { + return err + } + tmpl.Parse(string(infoPlist)) + + // Write the template to a buffer + var tpl bytes.Buffer + err = tmpl.Execute(&tpl, plistData) + if err != nil { + return err + } + filename := path.Join(b.fs.Cwd(), appname, "Contents", "Info.plist") + err = ioutil.WriteFile(filename, tpl.Bytes(), 0644) + if err != nil { + return err + } + + // Copy executable + target := path.Join(exeDir, exe) + err = b.fs.CopyFile(source, target) + if err != nil { + return err + } + + err = os.Chmod(target, 0755) + if err != nil { + return err + } + err = b.bundleIcon(resourceDir) + return err +} + +func (b *BundleHelper) bundleIcon(resourceDir string) error { + + // TODO: Read this from project.json + const appIconFilename = "appicon.png" + + srcIcon := path.Join(b.fs.Cwd(), appIconFilename) + + // Check if appicon.png exists + if !b.fs.FileExists(srcIcon) { + + // Install default icon + iconfile := filepath.Join(b.getBundleFileBaseDir(), "icon.png") + iconData, err := ioutil.ReadFile(iconfile) + if err != nil { + return err + } + err = ioutil.WriteFile(srcIcon, iconData, 0644) + if err != nil { + return err + } + } + + tgtBundle := path.Join(resourceDir, "iconfile.icns") + imageFile, err := os.Open(srcIcon) + if err != nil { + return err + } + defer imageFile.Close() + srcImg, _, err := image.Decode(imageFile) + if err != nil { + return err + + } + dest, err := os.Create(tgtBundle) + if err != nil { + return err + + } + defer dest.Close() + if err := icns.Encode(dest, srcImg); err != nil { + return err + + } + return nil +} diff --git a/cmd/program.go b/cmd/program.go index c92d6b382..23e3c8a92 100644 --- a/cmd/program.go +++ b/cmd/program.go @@ -2,17 +2,23 @@ package cmd import ( "bytes" + "fmt" "os/exec" "path/filepath" + "strings" "syscall" ) // ProgramHelper - Utility functions around installed applications -type ProgramHelper struct{} +type ProgramHelper struct { + shell *ShellHelper +} // NewProgramHelper - Creates a new ProgramHelper func NewProgramHelper() *ProgramHelper { - return &ProgramHelper{} + return &ProgramHelper{ + shell: NewShellHelper(), + } } // IsInstalled tries to determine if the given binary name is installed @@ -83,3 +89,31 @@ func (p *Program) Run(vars ...string) (stdout, stderr string, exitCode int, err } return } + +// InstallGoPackage installs the given Go package +func (p *ProgramHelper) InstallGoPackage(packageName string) error { + args := strings.Split("get -u "+packageName, " ") + _, stderr, err := p.shell.Run("go", args...) + if err != nil { + fmt.Println(stderr) + } + return err +} + +// RunCommand runs the given command +func (p *ProgramHelper) RunCommand(command string) error { + args := strings.Split(command, " ") + program := args[0] + // TODO: Run FindProgram here and get the full path to the exe + program, err := exec.LookPath(program) + if err != nil { + fmt.Printf("ERROR: Looks like '%s' isn't installed. Please install and try again.", program) + return err + } + args = args[1:] + _, stderr, err := p.shell.Run(program, args...) + if err != nil { + fmt.Println(stderr) + } + return err +} diff --git a/cmd/shell.go b/cmd/shell.go new file mode 100644 index 000000000..b07ef451a --- /dev/null +++ b/cmd/shell.go @@ -0,0 +1,27 @@ +package cmd + +import ( + "bytes" + "os/exec" +) + +// ShellHelper helps with Shell commands +type ShellHelper struct { +} + +// NewShellHelper creates a new ShellHelper! +func NewShellHelper() *ShellHelper { + return &ShellHelper{} +} + +// Run the given command +func (sh *ShellHelper) Run(command string, vars ...string) (stdout, stderr string, err error) { + cmd := exec.Command(command, vars...) + var stdo, stde bytes.Buffer + cmd.Stdout = &stdo + cmd.Stderr = &stde + err = cmd.Run() + stdout = string(stdo.Bytes()) + stderr = string(stde.Bytes()) + return +} diff --git a/cmd/templates.go b/cmd/templates.go index 1647cae2b..d206ee448 100644 --- a/cmd/templates.go +++ b/cmd/templates.go @@ -16,6 +16,7 @@ import ( const templateSuffix = ".template" +// TemplateHelper helps with creating projects type TemplateHelper struct { system *SystemHelper fs *FSHelper @@ -25,12 +26,14 @@ type TemplateHelper struct { metadataFilename string } +// Template defines a single template type Template struct { Name string Dir string Metadata map[string]interface{} } +// NewTemplateHelper creates a new template helper func NewTemplateHelper() *TemplateHelper { result := TemplateHelper{ system: NewSystemHelper(), @@ -45,6 +48,7 @@ func NewTemplateHelper() *TemplateHelper { return &result } +// GetTemplateNames returns a map of all available templates func (t *TemplateHelper) GetTemplateNames() (map[string]string, error) { templateDirs, err := t.fs.GetSubdirs(t.templateDir) if err != nil { @@ -53,6 +57,8 @@ func (t *TemplateHelper) GetTemplateNames() (map[string]string, error) { return templateDirs, nil } +// GetTemplateDetails returns a map of Template structs containing details +// of the found templates func (t *TemplateHelper) GetTemplateDetails() (map[string]*Template, error) { templateDirs, err := t.fs.GetSubdirs(t.templateDir) if err != nil { @@ -81,6 +87,7 @@ func (t *TemplateHelper) GetTemplateDetails() (map[string]*Template, error) { return result, nil } +// LoadMetadata loads the template's 'metadata.json' file func (t *TemplateHelper) LoadMetadata(dir string) (map[string]interface{}, error) { templateFile := filepath.Join(dir, t.metadataFilename) result := make(map[string]interface{}) @@ -95,6 +102,7 @@ func (t *TemplateHelper) LoadMetadata(dir string) (map[string]interface{}, error return result, err } +// TemplateExists returns true if the given template name exists func (t *TemplateHelper) TemplateExists(templateName string) (bool, error) { templates, err := t.GetTemplateNames() if err != nil { @@ -104,6 +112,8 @@ func (t *TemplateHelper) TemplateExists(templateName string) (bool, error) { return exists, nil } +// InstallTemplate installs the template given in the project options to the +// project path given func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error { // Get template files diff --git a/cmd/wails/3_build.go b/cmd/wails/3_build.go new file mode 100644 index 000000000..deb4282cd --- /dev/null +++ b/cmd/wails/3_build.go @@ -0,0 +1,225 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "strings" + + "github.com/leaanthony/spinner" + "github.com/wailsapp/wails/cmd" +) + +func init() { + + var bundle = false + var forceRebuild = false + buildSpinner := spinner.NewSpinner() + buildSpinner.SetSpinSpeed(50) + + commandDescription := `This command will check to ensure all pre-requistes are installed prior to building. If not, it will attempt to install them. Building comprises of a number of steps: install frontend dependencies, build frontend, pack frontend, compile main application.` + initCmd := app.Command("build", "Builds your Wails project"). + LongDescription(commandDescription). + BoolFlag("b", "Bundle application on successful build", &bundle). + BoolFlag("f", "Force rebuild of application components", &forceRebuild) + + initCmd.Action(func() error { + log := cmd.NewLogger() + message := "Building Application" + if forceRebuild { + message += " (force rebuild)" + } + log.WhiteUnderline(message) + + // Project options + projectOptions := &cmd.ProjectOptions{} + + // Check we are in project directory + // Check project.json loads correctly + fs := cmd.NewFSHelper() + err := projectOptions.LoadConfig(fs.Cwd()) + if err != nil { + return err + } + + // Validate config + // Check if we have a frontend + if projectOptions.FrontEnd != nil { + if projectOptions.FrontEnd.Dir == "" { + return fmt.Errorf("Frontend directory not set in project.json") + } + if projectOptions.FrontEnd.Build == "" { + return fmt.Errorf("Frontend build command not set in project.json") + } + if projectOptions.FrontEnd.Install == "" { + return fmt.Errorf("Frontend install command not set in project.json") + } + } + + // Check pre-requisites are installed + + // Program checker + program := cmd.NewProgramHelper() + + if projectOptions.FrontEnd != nil { + // npm + if !program.IsInstalled("npm") { + return fmt.Errorf("it appears npm is not installed. Please install and run again") + } + } + + // packr + if !program.IsInstalled("packr") { + buildSpinner.Start("Installing packr...") + err := program.InstallGoPackage("github.com/gobuffalo/packr/...") + if err != nil { + buildSpinner.Error() + return err + } + buildSpinner.Success() + } + + // Save project directory + projectDir := fs.Cwd() + + // Install backend deps - needed? + if projectOptions.FrontEnd != nil { + // Install frontend deps + err = os.Chdir(projectOptions.FrontEnd.Dir) + if err != nil { + return err + } + + // Check if frontend deps have been updated + buildSpinner.Start("Installing frontend dependencies...") + + requiresNPMInstall := true + + // Read in package.json MD5 + packageJSONMD5, err := fs.FileMD5("package.json") + if err != nil { + return err + } + + const md5sumFile = "package.json.md5" + + // If we aren't forcing the install and the md5sum file exists + if !forceRebuild && fs.FileExists(md5sumFile) { + // Yes - read contents + savedMD5sum, err := fs.LoadAsString(md5sumFile) + // File exists + if err == nil { + // Compare md5 + if savedMD5sum == packageJSONMD5 { + // Same - no need for reinstall + requiresNPMInstall = false + buildSpinner.Success("Skipped frontend dependencies (-f to force rebuild)") + } + } + } + + // Md5 sum package.json + // Different? Build + if requiresNPMInstall || forceRebuild { + // Install dependencies + err = program.RunCommand(projectOptions.FrontEnd.Install) + if err != nil { + buildSpinner.Error() + return err + } + buildSpinner.Success() + + // Update md5sum file + ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644) + } + + // Build frontend + buildSpinner.Start("Building frontend...") + err = program.RunCommand(projectOptions.FrontEnd.Build) + if err != nil { + buildSpinner.Error() + return err + } + buildSpinner.Success() + } + + // Run packr in project directory + err = os.Chdir(projectDir) + if err != nil { + buildSpinner.Error() + return err + } + + // Support build tags + buildTags := []string{} + + // Do we have any frameworks specified? + if projectOptions.Framework != nil { + buildSpinner.Start() + buildSpinner.Success("Compiling support for " + projectOptions.Framework.Name) + buildTags = append(buildTags, projectOptions.Framework.BuildTag) + } + + // // Initialise Go Module - if go.mod doesn't exist + // if !fs.FileExists("go.mod") { + // buildSpinner.Start("Initialising Go module...") + // err = program.RunCommand("go mod init " + projectOptions.BinaryName) + // if err != nil { + // buildSpinner.Error() + // return err + // } + // buildSpinner.Success() + // } + + buildSpinner.Start("Installing Dependencies...") + installCommand := "go get" + err = program.RunCommand(installCommand) + if err != nil { + buildSpinner.Error() + return err + } + buildSpinner.Success() + + buildSpinner.Start("Packing + Compiling project...") + + buildCommand := "packr build" + + // Add build tags + if len(buildTags) > 0 { + buildCommand += fmt.Sprintf(" --tags '%s'", strings.Join(buildTags, " ")) + } + + if projectOptions.BinaryName != "" { + buildCommand += " -o " + projectOptions.BinaryName + } + + // If we are forcing a rebuild + if forceRebuild { + buildCommand += " -a" + } + + err = program.RunCommand(buildCommand) + if err != nil { + buildSpinner.Error() + return err + } + buildSpinner.Success() + + if bundle == false { + logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name) + return nil + } + + // Bundle app + buildSpinner.Start("Bundling Application") + bundler := cmd.NewBundleHelper() + err = bundler.Bundle(projectOptions) + if err != nil { + buildSpinner.Error() + return err + } + buildSpinner.Success() + logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name) + return nil + }) +} diff --git a/event_manager.go b/event_manager.go new file mode 100644 index 000000000..6520ee840 --- /dev/null +++ b/event_manager.go @@ -0,0 +1,148 @@ +package wails + +import ( + "fmt" + "sync" +) + +// eventManager handles and processes events +type eventManager struct { + incomingEvents chan *eventData + listeners map[string][]*eventListener + exit bool + log *CustomLogger + renderer Renderer // Messages will be dispatched to the frontend +} + +// newEventManager creates a new event manager with a 100 event buffer +func newEventManager() *eventManager { + return &eventManager{ + incomingEvents: make(chan *eventData, 100), + listeners: make(map[string][]*eventListener), + exit: false, + log: newCustomLogger("Events"), + } +} + +// PushEvent places the given event on to the event queue +func (e *eventManager) PushEvent(eventData *eventData) { + e.incomingEvents <- eventData +} + +// eventListener holds a callback function which is invoked when +// the event listened for is emitted. It has a counter which indicates +// how the total number of events it is interested in. A value of zero +// means it does not expire (default). +type eventListener struct { + callback func(...interface{}) // Function to call with emitted event data + counter int // Expire after counter callbacks. 0 = infinite + expired bool // Indicates if the listener has expired +} + +// Creates a new event listener from the given callback function +func (e *eventManager) addEventListener(eventName string, callback func(...interface{}), counter int) error { + + // Sanity check inputs + if callback == nil { + return fmt.Errorf("nil callback bassed to addEventListener") + } + + // Check event has been registered before + if e.listeners[eventName] == nil { + e.listeners[eventName] = []*eventListener{} + } + + // Create the callback + listener := &eventListener{ + callback: callback, + counter: counter, + } + + // Register listener + e.listeners[eventName] = append(e.listeners[eventName], listener) + + // All good mate + return nil +} + +func (e *eventManager) On(eventName string, callback func(...interface{})) { + // Add a persistent eventListener (counter = 0) + e.addEventListener(eventName, callback, 0) +} + +// Emit broadcasts the given event to the subscribed listeners +func (e *eventManager) Emit(eventName string, optionalData ...interface{}) { + e.incomingEvents <- &eventData{Name: eventName, Data: optionalData} +} + +// Starts the event manager's queue processing +func (e *eventManager) start(renderer Renderer) { + + e.log.Info("Starting") + + // Store renderer + e.renderer = renderer + + // Set up waitgroup so we can wait for goroutine to start + var wg sync.WaitGroup + wg.Add(1) + + // Run main loop in seperate goroutine + go func() { + wg.Done() + e.log.Info("Listening") + for e.exit == false { + // TODO: Listen for application exit + select { + case event := <-e.incomingEvents: + e.log.DebugFields("Got Event", Fields{ + "data": event.Data, + "name": event.Name, + }) + + // Notify renderer + e.renderer.NotifyEvent(event) + + // Notify Go listeners + var listenersToRemove []*eventListener + + // Iterate listeners + for _, listener := range e.listeners[event.Name] { + + // Call listener, perhaps with data + if event.Data == nil { + go listener.callback() + } else { + unpacked := event.Data.([]interface{}) + go listener.callback(unpacked...) + } + + // Update listen counter + if listener.counter > 0 { + listener.counter = listener.counter - 1 + if listener.counter == 0 { + listener.expired = true + } + } + } + + // Remove expired listners in place + if len(listenersToRemove) > 0 { + listeners := e.listeners[event.Name][:0] + for _, listener := range listeners { + if !listener.expired { + listeners = append(listeners, listener) + } + } + } + } + } + }() + + // Wait for goroutine to start + wg.Wait() +} + +func (e *eventManager) stop() { + e.exit = true +} diff --git a/go.mod b/go.mod index 92c424322..1d6eabdf5 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,14 @@ module github.com/wailsapp/wails require ( github.com/AlecAivazis/survey v1.7.1 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc + github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc // indirect + github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac + github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947 // indirect github.com/fatih/color v1.7.0 + github.com/go-playground/colors v1.2.0 github.com/gobuffalo/packr v1.21.9 + github.com/gorilla/websocket v1.4.0 + github.com/jackmordaunt/icns v1.0.0 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/leaanthony/spinner v0.4.0 github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0 // indirect @@ -13,5 +19,8 @@ require ( github.com/mattn/go-isatty v0.0.4 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/mitchellh/go-homedir v1.0.0 + github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect + github.com/sirupsen/logrus v1.2.0 + golang.org/x/net v0.0.0-20190107155100-1a61f4433d85 // indirect gopkg.in/AlecAivazis/survey.v1 v1.7.1 // indirect ) diff --git a/go.sum b/go.sum index 35b380abd..a36d9e0c1 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,12 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc h1:VBS1z48BFEe00G81z8MKOtwX7f/ISkuH38NscT8iVPw= +github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc/go.mod h1:ABJPuor7YlcsHmvJ1QxX38e2NcufLY3hm0yXv+cy9sI= +github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac h1:DpMwFluHWoZpV9ex5XjkWO4HyCz5HLVI8XbHw0FhHi4= +github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac/go.mod h1:XsAE+b4rOZc8gvgsgF+wU75mNBvBcyED1wdd9PBLlJ0= +github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947 h1:Fm10/KNuoAyBm2P5P5H91Xy21hGcZnBdjR+cMdytv1M= +github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947/go.mod h1:Dv9D0NUlAsaQcGQZa5kc5mqR9ua72SmA8VXi4cd+cBw= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -22,6 +28,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-playground/colors v1.2.0 h1:0EdjTXKrr2g1L/LQTYtIqabeHpZuGZz1U4osS1T8+5M= +github.com/go-playground/colors v1.2.0/go.mod h1:miw1R2JIE19cclPxsXqNdzLZsk4DP4iF+m88bRc7kfM= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/gobuffalo/buffalo v0.12.8-0.20181004233540-fac9bb505aa8/go.mod h1:sLyT7/dceRXJUxSsE813JTQtA3Eb1vjxWfo/N//vXIY= github.com/gobuffalo/buffalo v0.13.0/go.mod h1:Mjn1Ba9wpIbpbrD+lIDMy99pQ0H0LiddMIIDGse7qT4= @@ -185,11 +193,15 @@ github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5 github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= +github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ= +github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo= github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= @@ -246,6 +258,8 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -271,6 +285,7 @@ github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go. github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.1.0/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= +github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= @@ -301,6 +316,7 @@ golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -314,7 +330,10 @@ golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181207154023-610586996380 h1:zPQexyRtNYBc7bcHmehl1dH6TB3qn8zytv8cBGLDNY0= golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190107155100-1a61f4433d85 h1:3DfFuyqY+mca6oIDfim5rft3+Kl/CHLe7RdPrUMzwv0= +golang.org/x/net v0.0.0-20190107155100-1a61f4433d85/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -333,6 +352,7 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181106135930-3a76605856fd/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e h1:njOxP/wVblhCLIUhjHXf6X+dzTt5OQ3vMQo9mkOIKIo= golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/ipc_call.go b/ipc_call.go new file mode 100644 index 000000000..4baa224f1 --- /dev/null +++ b/ipc_call.go @@ -0,0 +1,38 @@ +package wails + +import ( + "fmt" +) + +type callData struct { + BindingName string `json:"bindingName"` + Data string `json:"data,omitempty"` +} + +func init() { + messageProcessors["call"] = processCallData +} + +func processCallData(message *ipcMessage) (*ipcMessage, error) { + + var payload callData + + // Decode binding call data + payloadMap := message.Payload.(map[string]interface{}) + + // Check for binding name + if payloadMap["bindingName"] == nil { + return nil, fmt.Errorf("bindingName not given in call") + } + payload.BindingName = payloadMap["bindingName"].(string) + + // Check for data + if payloadMap["data"] != nil { + payload.Data = payloadMap["data"].(string) + } + + // Reassign payload to decoded data + message.Payload = &payload + + return message, nil +} diff --git a/ipc_event.go b/ipc_event.go new file mode 100644 index 000000000..416b160ef --- /dev/null +++ b/ipc_event.go @@ -0,0 +1,40 @@ +package wails + +import ( + "encoding/json" +) + +type eventData struct { + Name string `json:"name"` + Data interface{} `json:"data"` +} + +// Register the message handler +func init() { + messageProcessors["event"] = processEventData +} + +// This processes the given event message +func processEventData(message *ipcMessage) (*ipcMessage, error) { + + // TODO: Is it worth double checking this is actually an event message, + // even though that's done by the caller? + var payload eventData + + // Decode event data + payloadMap := message.Payload.(map[string]interface{}) + payload.Name = payloadMap["name"].(string) + + // decode the payload data + var data []interface{} + err := json.Unmarshal([]byte(payloadMap["data"].(string)), &data) + if err != nil { + return nil, err + } + payload.Data = data + + // Reassign payload to decoded data + message.Payload = &payload + + return message, nil +} diff --git a/ipc_log.go b/ipc_log.go new file mode 100644 index 000000000..ba35104fc --- /dev/null +++ b/ipc_log.go @@ -0,0 +1,27 @@ +package wails + +type logData struct { + Level string `json:"level"` + Message string `json:"string"` +} + +// Register the message handler +func init() { + messageProcessors["log"] = processLogData +} + +// This processes the given log message +func processLogData(message *ipcMessage) (*ipcMessage, error) { + + var payload logData + + // Decode event data + payloadMap := message.Payload.(map[string]interface{}) + payload.Level = payloadMap["level"].(string) + payload.Message = payloadMap["message"].(string) + + // Reassign payload to decoded data + message.Payload = &payload + + return message, nil +} diff --git a/ipc_manager.go b/ipc_manager.go new file mode 100644 index 000000000..430c2b1ce --- /dev/null +++ b/ipc_manager.go @@ -0,0 +1,162 @@ +package wails + +import ( + "fmt" +) + +type ipcManager struct { + renderer Renderer // The renderer + messageQueue chan *ipcMessage + // quitChannel chan struct{} + // signals chan os.Signal + log *CustomLogger + eventManager *eventManager + bindingManager *bindingManager +} + +func newIPCManager() *ipcManager { + result := &ipcManager{ + messageQueue: make(chan *ipcMessage, 100), + // quitChannel: make(chan struct{}), + // signals: make(chan os.Signal, 1), + log: newCustomLogger("IPC"), + } + return result +} + +// Sets the renderer, returns the dispatch function +func (i *ipcManager) bindRenderer(renderer Renderer) { + i.renderer = renderer +} + +func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingManager) { + + // Store manager references + i.eventManager = eventManager + i.bindingManager = bindingManager + + i.log.Info("Starting") + // signal.Notify(manager.signals, os.Interrupt) + go func() { + running := true + for running { + select { + case incomingMessage := <-i.messageQueue: + i.log.DebugFields("Processing message", Fields{ + "1D": &incomingMessage, + }) + switch incomingMessage.Type { + case "call": + callData := incomingMessage.Payload.(*callData) + i.log.DebugFields("Processing call", Fields{ + "1D": &incomingMessage, + "bindingName": callData.BindingName, + "data": callData.Data, + }) + go func() { + result, err := bindingManager.processCall(callData) + i.log.DebugFields("processed call", Fields{"result": result, "err": err}) + if err != nil { + incomingMessage.ReturnError(err.Error()) + } else { + incomingMessage.ReturnSuccess(result) + } + i.log.DebugFields("Finished processing call", Fields{ + "1D": &incomingMessage, + }) + }() + case "event": + + // Extract event data + eventData := incomingMessage.Payload.(*eventData) + + // Log + i.log.DebugFields("Processing event", Fields{ + "name": eventData.Name, + "data": eventData.Data, + }) + + // Push the event to the event manager + i.eventManager.PushEvent(eventData) + + // Log + i.log.DebugFields("Finished processing event", Fields{ + "name": eventData.Name, + }) + case "log": + logdata := incomingMessage.Payload.(*logData) + switch logdata.Level { + case "info": + logger.Info(logdata.Message) + case "debug": + logger.Debug(logdata.Message) + case "warning": + logger.Warning(logdata.Message) + case "error": + logger.Error(logdata.Message) + case "fatal": + logger.Fatal(logdata.Message) + default: + i.log.ErrorFields("Invalid log level sent", Fields{ + "level": logdata.Level, + "message": logdata.Message, + }) + } + default: + i.log.Debugf("bad message sent to MessageQueue! Unknown type: %s", incomingMessage.Type) + } + + // Log + i.log.DebugFields("Finished processing message", Fields{ + "1D": &incomingMessage, + }) + // case <-manager.quitChannel: + // Debug("[MessageQueue] Quit caught") + // running = false + // case <-manager.signals: + // Debug("[MessageQueue] Signal caught") + // running = false + } + } + i.log.Debug("Stopping") + }() +} + +// Dispatch receives JSON encoded messages from the renderer. +// It processes the message to ensure that it is valid and places +// the processed message on the message queue +func (i *ipcManager) Dispatch(message string) { + + // Create a new IPC Message + incomingMessage, err := newIPCMessage(message, i.SendResponse) + if err != nil { + i.log.ErrorFields("Could not understand incoming message! ", map[string]interface{}{ + "message": message, + "error": err, + }) + return + } + + // Put message on queue + i.log.DebugFields("Message received", map[string]interface{}{ + "type": incomingMessage.Type, + "payload": incomingMessage.Payload, + }) + + // Put incoming message on the message queue + i.messageQueue <- incomingMessage +} + +// SendResponse sends the given response back to the frontend +func (i *ipcManager) SendResponse(response *ipcResponse) error { + + // Serialise the Message + data, err := response.Serialise() + if err != nil { + fmt.Printf(err.Error()) + return err + } + + // Call back to the front end + return i.renderer.Callback(data) +} diff --git a/ipc_message.go b/ipc_message.go new file mode 100644 index 000000000..5d792bc59 --- /dev/null +++ b/ipc_message.go @@ -0,0 +1,93 @@ +package wails + +import ( + "encoding/json" + "fmt" +) + +// Message handler +type messageProcessorFunc func(*ipcMessage) (*ipcMessage, error) + +var messageProcessors = make(map[string]messageProcessorFunc) + +// ipcMessage is the struct version of the Message sent from the frontend. +// The payload has the specialised message data +type ipcMessage struct { + Type string `json:"type"` + Payload interface{} `json:"payload"` + CallbackID string `json:"callbackid,omitempty"` + sendResponse func(*ipcResponse) error +} + +func parseMessage(incomingMessage string) (*ipcMessage, error) { + // Parse message + var message ipcMessage + err := json.Unmarshal([]byte(incomingMessage), &message) + return &message, err +} + +func newIPCMessage(incomingMessage string, responseFunction func(*ipcResponse) error) (*ipcMessage, error) { + + // Parse the Message + message, err := parseMessage(incomingMessage) + if err != nil { + return nil, err + } + + // Check message type is valid + messageProcessor := messageProcessors[message.Type] + if messageProcessor == nil { + return nil, fmt.Errorf("unknown message type: %s", message.Type) + } + + // Process message payload + message, err = messageProcessor(message) + if err != nil { + return nil, err + } + + // Set the response function + message.sendResponse = responseFunction + + return message, nil +} + +// hasCallbackID checks if the message can send an error back to the frontend +func (m *ipcMessage) hasCallbackID() error { + if m.CallbackID == "" { + return fmt.Errorf("attempted to return error to message with no Callback ID") + } + return nil +} + +// ReturnError returns an error back to the frontend +func (m *ipcMessage) ReturnError(format string, args ...interface{}) error { + + // Ignore ReturnError if no callback ID given + err := m.hasCallbackID() + if err != nil { + return err + } + + // Create response + response := newErrorResponse(m.CallbackID, fmt.Sprintf(format, args...)) + + // Send response + return m.sendResponse(response) +} + +// ReturnSuccess returns a success message back with the given data +func (m *ipcMessage) ReturnSuccess(data interface{}) error { + + // Ignore ReturnSuccess if no callback ID given + err := m.hasCallbackID() + if err != nil { + return err + } + + // Create the response + response := newSuccessResponse(m.CallbackID, data) + + // Send response + return m.sendResponse(response) +} diff --git a/ipc_response.go b/ipc_response.go new file mode 100644 index 000000000..945819719 --- /dev/null +++ b/ipc_response.go @@ -0,0 +1,43 @@ +package wails + +import ( + "encoding/json" + "strings" +) + +// ipcResponse contains the response data from an RPC call +type ipcResponse struct { + CallbackID string `json:"callbackid"` + ErrorMessage string `json:"error,omitempty"` + Data interface{} `json:"data,omitempty"` +} + +// newErrorResponse returns the given error message to the frontend with the callbackid +func newErrorResponse(callbackID string, errorMessage string) *ipcResponse { + // Create response object + result := &ipcResponse{ + CallbackID: callbackID, + ErrorMessage: errorMessage, + } + return result +} + +// newSuccessResponse returns the given data to the frontend with the callbackid +func newSuccessResponse(callbackID string, data interface{}) *ipcResponse { + + // Create response object + result := &ipcResponse{ + CallbackID: callbackID, + Data: data, + } + + return result +} + +// Serialise formats the response to a string +func (i *ipcResponse) Serialise() (string, error) { + b, err := json.Marshal(i) + result := strings.Replace(string(b), "\\", "\\\\", -1) + result = strings.Replace(result, "'", "\\'", -1) + return result, err +} diff --git a/log.go b/log.go new file mode 100644 index 000000000..69513ab1e --- /dev/null +++ b/log.go @@ -0,0 +1,40 @@ +package wails + +import ( + "os" + "strings" + + log "github.com/sirupsen/logrus" +) + +// Global logger reference +var logger = log.New() + +// Fields is used by the customLogger object to output +// fields along with a message +type Fields map[string]interface{} + +// Default options for the global logger +func init() { + logger.SetOutput(os.Stdout) + logger.SetLevel(log.DebugLevel) +} + +// Sets the log level to the given level +func setLogLevel(level string) { + switch strings.ToLower(level) { + case "info": + logger.SetLevel(log.InfoLevel) + case "debug": + logger.SetLevel(log.DebugLevel) + case "warn": + logger.SetLevel(log.WarnLevel) + case "fatal": + logger.SetLevel(log.FatalLevel) + case "panic": + logger.SetLevel(log.PanicLevel) + default: + logger.SetLevel(log.DebugLevel) + logger.Warnf("Log level '%s' not recognised. Setting to Debug.", level) + } +} diff --git a/log_custom.go b/log_custom.go new file mode 100644 index 000000000..57bdbb90c --- /dev/null +++ b/log_custom.go @@ -0,0 +1,82 @@ +package wails + +type CustomLogger struct { + prefix string +} + +func newCustomLogger(prefix string) *CustomLogger { + return &CustomLogger{ + prefix: "[" + prefix + "] ", + } +} + +func (c *CustomLogger) Info(message string) { + logger.Info(c.prefix + message) +} + +func (c *CustomLogger) Infof(message string, args ...interface{}) { + logger.Infof(c.prefix+message, args...) +} + +func (c *CustomLogger) InfoFields(message string, fields Fields) { + logger.WithFields(map[string]interface{}(fields)).Info(c.prefix + message) +} + +func (c *CustomLogger) Debug(message string) { + logger.Debug(c.prefix + message) +} + +func (c *CustomLogger) Debugf(message string, args ...interface{}) { + logger.Debugf(c.prefix+message, args...) +} + +func (c *CustomLogger) DebugFields(message string, fields Fields) { + logger.WithFields(map[string]interface{}(fields)).Debug(c.prefix + message) +} + +func (c *CustomLogger) Warn(message string) { + logger.Warn(c.prefix + message) +} + +func (c *CustomLogger) Warnf(message string, args ...interface{}) { + logger.Warnf(c.prefix+message, args...) +} + +func (c *CustomLogger) WarnFields(message string, fields Fields) { + logger.WithFields(map[string]interface{}(fields)).Warn(c.prefix + message) +} + +func (c *CustomLogger) Error(message string) { + logger.Error(c.prefix + message) +} + +func (c *CustomLogger) Errorf(message string, args ...interface{}) { + logger.Errorf(c.prefix+message, args...) +} + +func (c *CustomLogger) ErrorFields(message string, fields Fields) { + logger.WithFields(map[string]interface{}(fields)).Error(c.prefix + message) +} + +func (c *CustomLogger) Fatal(message string) { + logger.Fatal(c.prefix + message) +} + +func (c *CustomLogger) Fatalf(message string, args ...interface{}) { + logger.Fatalf(c.prefix+message, args...) +} + +func (c *CustomLogger) FatalFields(message string, fields Fields) { + logger.WithFields(map[string]interface{}(fields)).Fatal(c.prefix + message) +} +func (c *CustomLogger) Panic(message string) { + logger.Panic(c.prefix + message) +} + +func (c *CustomLogger) Panicf(message string, args ...interface{}) { + logger.Panicf(c.prefix+message, args...) +} + +func (c *CustomLogger) PanicFields(message string, fields Fields) { + logger.WithFields(map[string]interface{}(fields)).Panic(c.prefix + message) +} diff --git a/renderer.go b/renderer.go new file mode 100644 index 000000000..0c14eb154 --- /dev/null +++ b/renderer.go @@ -0,0 +1,31 @@ +package wails + +// Renderer is an interface describing a Wails target to render the app to +type Renderer interface { + Initialise(*AppConfig, *ipcManager, *eventManager) error + Run() error + + // Binding + NewBinding(bindingName string) error + Callback(data string) error + + // Events + NotifyEvent(eventData *eventData) error + + // Injection + InjectFramework(js string, css string) + AddJSList(js []string) + AddCSSList(css []string) + + // Dialog Runtime + SelectFile() string + SelectDirectory() string + SelectSaveFile() string + + // Window Runtime + SetColour(string) error + Fullscreen() + UnFullscreen() + SetTitle(title string) + Close() +} diff --git a/renderer_headless.go b/renderer_headless.go new file mode 100644 index 000000000..71d99b072 --- /dev/null +++ b/renderer_headless.go @@ -0,0 +1,279 @@ +package wails + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + + "github.com/dchest/htmlmin" + "github.com/gobuffalo/packr" + "github.com/gorilla/websocket" +) + +var headlessAssets = packr.NewBox("./assets/headless") +var defaultAssets = packr.NewBox("./assets/default") + +// Window defines the main application window +// Default values in [] +type Headless struct { + // Common + log *CustomLogger + ipcManager *ipcManager + appConfig *AppConfig + eventManager *eventManager + bindingCache []string + frameworkJS string + frameworkCSS string + jsCache []string + cssCache []string + + // Headless specific + initialisationJS []string + server *http.Server + theConnection *websocket.Conn +} + +func (h *Headless) Initialise(appConfig *AppConfig, ipcManager *ipcManager, eventManager *eventManager) error { + h.ipcManager = ipcManager + h.appConfig = appConfig + h.eventManager = eventManager + h.log = newCustomLogger("Headless") + return nil +} + +func (h *Headless) evalJS(js string) error { + if h.theConnection == nil { + h.initialisationJS = append(h.initialisationJS, js) + } else { + h.sendMessage(h.theConnection, js) + } + + return nil +} + +func (h *Headless) injectCSS(css string) { + // Minify css to overcome issues in the browser with carriage returns + minified, err := htmlmin.Minify([]byte(css), &htmlmin.Options{ + MinifyStyles: true, + }) + if err != nil { + h.log.Fatal("Unable to minify CSS: " + css) + } + minifiedCSS := string(minified) + minifiedCSS = strings.Replace(minifiedCSS, "'", "\\'", -1) + minifiedCSS = strings.Replace(minifiedCSS, "\n", " ", -1) + inject := fmt.Sprintf("wails._.injectCSS('%s')", minifiedCSS) + h.evalJS(inject) +} + +func (h *Headless) rootHandler(w http.ResponseWriter, r *http.Request) { + indexHTML := headlessAssets.String("index.html") + fmt.Fprintf(w, "%s", indexHTML) +} + +func (h *Headless) wsHandler(w http.ResponseWriter, r *http.Request) { + conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024) + if err != nil { + http.Error(w, "Could not open websocket connection", http.StatusBadRequest) + } + h.theConnection = conn + h.log.Infof("Connection %p accepted.", h.theConnection) + conn.SetCloseHandler(func(int, string) error { + h.log.Infof("Connection %p dropped.", h.theConnection) + h.theConnection = nil + return nil + }) + go h.start(conn) +} + +func (h *Headless) sendMessage(conn *websocket.Conn, msg string) { + if err := conn.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil { + h.log.Error(err.Error()) + } +} + +func (h *Headless) start(conn *websocket.Conn) { + + // set external.invoke + h.log.Infof("Connected to frontend.") + + // If we are given an HTML fragment, load jquery + // for the html() function + if h.appConfig.isHTMLFragment { + // Inject jquery + jquery := defaultAssets.String("jquery.3.3.1.min.js") + h.evalJS(jquery) + } + + wailsRuntime := defaultAssets.String("wails.js") + h.evalJS(wailsRuntime) + + // Inject the initial JS + for _, js := range h.initialisationJS { + h.sendMessage(conn, js) + } + + // Inject bindings + for _, binding := range h.bindingCache { + h.evalJS(binding) + } + + // Inject Framework + if h.frameworkJS != "" { + h.evalJS(h.frameworkJS) + } + if h.frameworkCSS != "" { + h.injectCSS(h.frameworkCSS) + } + + // If given an HMTL fragment, mount it on #app + // Otherwise, replace the html tag + var injectHTML string + if h.appConfig.isHTMLFragment { + injectHTML = fmt.Sprintf("$('#app').html('%s')", h.appConfig.HTML) + } else { + injectHTML = fmt.Sprintf("$('html').html('%s')", h.appConfig.HTML) + } + h.evalJS(injectHTML) + + // Inject user CSS + if h.appConfig.CSS != "" { + outputCSS := fmt.Sprintf("%.45s", h.appConfig.CSS) + if len(outputCSS) > 45 { + outputCSS += "..." + } + h.log.DebugFields("Inject User CSS", Fields{"css": outputCSS}) + h.injectCSS(h.appConfig.CSS) + } + + // Inject all the CSS files that have been added + for _, css := range h.cssCache { + h.injectCSS(css) + } + + // Inject all the JS files that have been added + for _, js := range h.jsCache { + h.evalJS(js) + } + + // Inject user JS + if h.appConfig.JS != "" { + outputJS := fmt.Sprintf("%.45s", h.appConfig.JS) + if len(outputJS) > 45 { + outputJS += "..." + } + h.log.DebugFields("Inject User JS", Fields{"js": outputJS}) + h.evalJS(h.appConfig.JS) + } + + for { + messageType, buffer, err := conn.ReadMessage() + if messageType == -1 { + return + } + if err != nil { + h.log.Errorf("Error reading message: ", err) + continue + } + + h.log.Infof("Got message: %#v\n", string(buffer)) + + h.ipcManager.Dispatch(string(buffer)) + } +} + +func (h *Headless) Run() error { + h.server = &http.Server{Addr: ":34115"} + http.HandleFunc("/ws", h.wsHandler) + http.HandleFunc("/", h.rootHandler) + + h.log.Info("Started on port 34115") + h.log.Info("Application running at http://localhost:34115") + + err := h.server.ListenAndServe() + if err != nil { + h.log.Fatal(err.Error()) + } + return err +} + +func (h *Headless) NewBinding(methodName string) error { + objectCode := fmt.Sprintf("window.wails._.newBinding(`%s`);", methodName) + h.bindingCache = append(h.bindingCache, objectCode) + return nil +} + +func (h *Headless) InjectFramework(js, css string) { + h.frameworkJS = js + h.frameworkCSS = css +} + +func (h *Headless) SelectFile() string { + h.log.Error("SelectFile() unsupported in headless mode") + return "" +} +func (h *Headless) SelectDirectory() string { + h.log.Error("SelectDirectory() unsupported in headless mode") + return "" +} +func (h *Headless) SelectSaveFile() string { + h.log.Error("SelectSaveFile() unsupported in headless mode") + return "" +} +func (h *Headless) AddJSList(jsCache []string) { + h.jsCache = jsCache +} +func (h *Headless) AddCSSList(cssCache []string) { + h.cssCache = cssCache +} + +// Callback sends a callback to the frontend +func (h *Headless) Callback(data string) error { + callbackCMD := fmt.Sprintf("window.wails._.callback('%s');", data) + return h.evalJS(callbackCMD) +} + +func (h *Headless) NotifyEvent(event *eventData) error { + + // Look out! Nils about! + var err error + if event == nil { + err = fmt.Errorf("Sent nil event to renderer.webViewRenderer") + logger.Error(err) + return err + } + + // Default data is a blank array + data := []byte("[]") + + // Process event data + if event.Data != nil { + // Marshall the data + data, err = json.Marshal(event.Data) + if err != nil { + h.log.Errorf("Cannot unmarshall JSON data in event: %s ", err.Error()) + return err + } + } + + message := fmt.Sprintf("wails._.notify('%s','%s')", event.Name, data) + return h.evalJS(message) +} + +func (h *Headless) SetColour(colour string) error { + h.log.WarnFields("SetColour ignored for headless more", Fields{"col": colour}) + return nil +} +func (h *Headless) Fullscreen() { + h.log.Warn("Fullscreen() unsupported in headless mode") +} +func (h *Headless) UnFullscreen() { + h.log.Warn("UnFullscreen() unsupported in headless mode") +} +func (h *Headless) SetTitle(title string) { + h.log.WarnFields("SetTitle() unsupported in headless mode", Fields{"title": title}) +} +func (h *Headless) Close() { + h.log.Warn("Close() unsupported in headless mode") +} diff --git a/renderer_webview.go b/renderer_webview.go new file mode 100644 index 000000000..374bee9ad --- /dev/null +++ b/renderer_webview.go @@ -0,0 +1,383 @@ +package wails + +import ( + "encoding/json" + "fmt" + "math/rand" + "sync" + "time" + + "github.com/go-playground/colors" + "github.com/gobuffalo/packr" + "github.com/wailsapp/wails/webview" +) + +// Window defines the main application window +// Default values in [] +type webViewRenderer struct { + window webview.WebView // The webview object + ipc *ipcManager + log *CustomLogger + config *AppConfig + eventManager *eventManager + bindingCache []string + frameworkJS string + frameworkCSS string + + // This is a list of all the JS/CSS that needs injecting + // It will get injected in order + jsCache []string + cssCache []string +} + +// Initialise sets up the WebView +func (w *webViewRenderer) Initialise(config *AppConfig, ipc *ipcManager, eventManager *eventManager) error { + + // Store reference to eventManager + w.eventManager = eventManager + + // Set up logger + w.log = newCustomLogger("WebView") + + // Set up the dispatcher function + w.ipc = ipc + ipc.bindRenderer(w) + + // Save the config + w.config = config + + // Create the WebView instance + w.window = webview.NewWebview(webview.Settings{ + Width: config.Width, + Height: config.Height, + Title: config.Title, + Resizable: config.Resizable, + URL: config.defaultHTML, + Debug: !config.DisableInspector, + ExternalInvokeCallback: func(_ webview.WebView, message string) { + w.ipc.Dispatch(message) + }, + }) + + // SignalManager.OnExit(w.Exit) + + // Set colour + err := w.SetColour(config.Colour) + if err != nil { + return err + } + + w.log.Info("Initialised") + return nil +} + +func (w *webViewRenderer) SetColour(colour string) error { + color, err := colors.Parse(colour) + if err != nil { + return err + } + rgba := color.ToRGBA() + alpha := uint8(255 * rgba.A) + w.window.Dispatch(func() { + w.window.SetColor(rgba.R, rgba.G, rgba.B, alpha) + }) + + return nil +} + +// evalJS evaluates the given js in the WebView +// I should rename this to evilJS lol +func (w *webViewRenderer) evalJS(js string) error { + outputJS := fmt.Sprintf("%.45s", js) + if len(js) > 45 { + outputJS += "..." + } + w.log.DebugFields("Eval", Fields{"js": outputJS}) + // + w.window.Dispatch(func() { + w.window.Eval(js) + }) + return nil +} + +// evalJSSync evaluates the given js in the WebView synchronously +// Do not call this from the main thread or you'll nuke your app because +// you won't get the callback. +func (w *webViewRenderer) evalJSSync(js string) error { + + minified, err := escapeJS(js) + if err != nil { + return err + } + + outputJS := fmt.Sprintf("%.45s", js) + if len(js) > 45 { + outputJS += "..." + } + w.log.DebugFields("EvalSync", Fields{"js": outputJS}) + + ID := fmt.Sprintf("syncjs:%d:%d", time.Now().Unix(), rand.Intn(9999)) + var wg sync.WaitGroup + wg.Add(1) + + go func() { + exit := false + // We are done when we recieve the Callback ID + w.log.Debug("SyncJS: sending with ID = " + ID) + w.eventManager.On(ID, func(...interface{}) { + w.log.Debug("SyncJS: Got callback ID = " + ID) + wg.Done() + exit = true + }) + command := fmt.Sprintf("wails._.addScript('%s', '%s')", minified, ID) + w.window.Dispatch(func() { + w.window.Eval(command) + }) + for exit == false { + time.Sleep(time.Millisecond * 1) + } + }() + + wg.Wait() + + return nil +} + +// injectCSS adds the given CSS to the WebView +func (w *webViewRenderer) injectCSS(css string) { + w.window.Dispatch(func() { + w.window.InjectCSS(css) + }) +} + +// Quit the window +func (w *webViewRenderer) Exit() { + w.window.Exit() +} + +// Run the window main loop +func (w *webViewRenderer) Run() error { + + w.log.Info("Run()") + + // Runtime assets + assets := packr.NewBox("./assets/default") + + wailsRuntime := assets.String("wails.js") + w.evalJS(wailsRuntime) + + // Ping the wait channel when the wails runtime is loaded + w.eventManager.On("wails:loaded", func(...interface{}) { + + // Run this in a different go routine to free up the main process + go func() { + // Will we mount a custom component + // Inject jquery + jquery := assets.String("jquery.3.3.1.min.js") + w.evalJSSync(jquery) + + // Inject Bindings + for _, binding := range w.bindingCache { + w.evalJSSync(binding) + } + + // Inject Framework + if w.frameworkJS != "" { + w.evalJSSync(w.frameworkJS) + } + if w.frameworkCSS != "" { + w.injectCSS(w.frameworkCSS) + } + + // Do we have custom html? + // If given an HMTL fragment, mount it on #app + // Otherwise, replace the html tag + var injectHTML string + if w.config.isHTMLFragment { + injectHTML = fmt.Sprintf("$('#app').html('%s')", w.config.HTML) + } else { + injectHTML = fmt.Sprintf("$('html').html('%s')", w.config.HTML) + } + w.evalJSSync(injectHTML) + + // Inject user CSS + if w.config.CSS != "" { + outputCSS := fmt.Sprintf("%.45s", w.config.CSS) + if len(outputCSS) > 45 { + outputCSS += "..." + } + w.log.DebugFields("Inject User CSS", Fields{"css": outputCSS}) + w.injectCSS(w.config.CSS) + } + + // Inject all the CSS files that have been added + for _, css := range w.cssCache { + w.injectCSS(css) + } + + // Inject all the JS files that have been added + for _, js := range w.jsCache { + w.evalJSSync(js) + } + + // Inject user JS + if w.config.JS != "" { + outputJS := fmt.Sprintf("%.45s", w.config.JS) + if len(outputJS) > 45 { + outputJS += "..." + } + w.log.DebugFields("Inject User JS", Fields{"js": outputJS}) + w.evalJSSync(w.config.JS) + } + + // Emit that everything is loaded and ready + w.eventManager.Emit("wails:ready") + }() + }) + + // Kick off main window loop + w.window.Run() + + return nil +} + +// Binds the given method name with the front end +func (w *webViewRenderer) NewBinding(methodName string) error { + objectCode := fmt.Sprintf("window.wails._.newBinding('%s');", methodName) + w.bindingCache = append(w.bindingCache, objectCode) + return nil +} + +func (w *webViewRenderer) InjectFramework(js, css string) { + w.frameworkJS = js + w.frameworkCSS = css +} + +func (w *webViewRenderer) SelectFile() string { + var result string + + // We need to run this on the main thread, however Dispatch is + // non-blocking so we launch this in a goroutine and wait for + // dispatch to finish before returning the result + var wg sync.WaitGroup + wg.Add(1) + go func() { + w.window.Dispatch(func() { + result = w.window.Dialog(webview.DialogTypeOpen, 0, "Select File", "") + wg.Done() + }) + }() + wg.Wait() + return result +} + +func (w *webViewRenderer) SelectDirectory() string { + var result string + // We need to run this on the main thread, however Dispatch is + // non-blocking so we launch this in a goroutine and wait for + // dispatch to finish before returning the result + var wg sync.WaitGroup + wg.Add(1) + go func() { + w.window.Dispatch(func() { + result = w.window.Dialog(webview.DialogTypeOpen, webview.DialogFlagDirectory, "Select Directory", "") + wg.Done() + }) + }() + wg.Wait() + return result +} + +func (w *webViewRenderer) SelectSaveFile() string { + var result string + // We need to run this on the main thread, however Dispatch is + // non-blocking so we launch this in a goroutine and wait for + // dispatch to finish before returning the result + var wg sync.WaitGroup + wg.Add(1) + go func() { + w.window.Dispatch(func() { + result = w.window.Dialog(webview.DialogTypeSave, 0, "Save file", "") + wg.Done() + }) + }() + wg.Wait() + return result +} + +// AddJS adds a piece of Javascript to a cache that +// gets injected at runtime +func (w *webViewRenderer) AddJSList(jsCache []string) { + w.jsCache = jsCache +} + +// AddCSSList sets the cssCache to the given list of strings +func (w *webViewRenderer) AddCSSList(cssCache []string) { + w.cssCache = cssCache +} + +// Callback sends a callback to the frontend +func (w *webViewRenderer) Callback(data string) error { + callbackCMD := fmt.Sprintf("window.wails._.callback('%s');", data) + return w.evalJS(callbackCMD) +} + +func (w *webViewRenderer) NotifyEvent(event *eventData) error { + + // Look out! Nils about! + var err error + if event == nil { + err = fmt.Errorf("Sent nil event to renderer.webViewRenderer") + logger.Error(err) + return err + } + + // Default data is a blank array + data := []byte("[]") + + // Process event data + if event.Data != nil { + // Marshall the data + data, err = json.Marshal(event.Data) + if err != nil { + w.log.Errorf("Cannot unmarshall JSON data in event: %s ", err.Error()) + return err + } + } + + message := fmt.Sprintf("wails._.notify('%s','%s')", event.Name, data) + return w.evalJS(message) +} + +// Window +func (w *webViewRenderer) Fullscreen() { + if w.config.Resizable == false { + w.log.Warn("Cannot call Fullscreen() - App.Resizable = false") + return + } + w.window.Dispatch(func() { + w.window.SetFullscreen(true) + }) +} + +func (w *webViewRenderer) UnFullscreen() { + if w.config.Resizable == false { + w.log.Warn("Cannot call UnFullscreen() - App.Resizable = false") + return + } + w.window.Dispatch(func() { + w.window.SetFullscreen(false) + }) +} + +func (w *webViewRenderer) SetTitle(title string) { + w.window.Dispatch(func() { + w.window.SetTitle(title) + }) +} + +func (w *webViewRenderer) Close() { + w.window.Dispatch(func() { + w.window.Terminate() + }) +} diff --git a/runtime.go b/runtime.go new file mode 100644 index 000000000..38e383843 --- /dev/null +++ b/runtime.go @@ -0,0 +1,17 @@ +package wails + +type Runtime struct { + Events *RuntimeEvents + Log *RuntimeLog + Dialog *RuntimeDialog + Window *RuntimeWindow +} + +func newRuntime(eventManager *eventManager, renderer Renderer) *Runtime { + return &Runtime{ + Events: newRuntimeEvents(eventManager), + Log: newRuntimeLog(), + Dialog: newRuntimeDialog(renderer), + Window: newRuntimeWindow(renderer), + } +} diff --git a/runtime_dialog.go b/runtime_dialog.go new file mode 100644 index 000000000..75c126efe --- /dev/null +++ b/runtime_dialog.go @@ -0,0 +1,23 @@ +package wails + +type RuntimeDialog struct { + renderer Renderer +} + +func newRuntimeDialog(renderer Renderer) *RuntimeDialog { + return &RuntimeDialog{ + renderer: renderer, + } +} + +func (r *RuntimeDialog) SelectFile() string { + return r.renderer.SelectFile() +} + +func (r *RuntimeDialog) SelectDirectory() string { + return r.renderer.SelectDirectory() +} + +func (r *RuntimeDialog) SelectSaveFile() string { + return r.renderer.SelectSaveFile() +} diff --git a/runtime_events.go b/runtime_events.go new file mode 100644 index 000000000..187a60fab --- /dev/null +++ b/runtime_events.go @@ -0,0 +1,21 @@ +package wails + +type RuntimeEvents struct { + eventManager *eventManager +} + +func newRuntimeEvents(eventManager *eventManager) *RuntimeEvents { + return &RuntimeEvents{ + eventManager: eventManager, + } +} + +// On pass through +func (r *RuntimeEvents) On(eventName string, callback func(optionalData ...interface{})) { + r.eventManager.On(eventName, callback) +} + +// Emit pass through +func (r *RuntimeEvents) Emit(eventName string, optionalData ...interface{}) { + r.eventManager.Emit(eventName, optionalData) +} diff --git a/runtime_log.go b/runtime_log.go new file mode 100644 index 000000000..b2cbcdaab --- /dev/null +++ b/runtime_log.go @@ -0,0 +1,12 @@ +package wails + +type RuntimeLog struct { +} + +func newRuntimeLog() *RuntimeLog { + return &RuntimeLog{} +} + +func (r *RuntimeLog) New(prefix string) *CustomLogger { + return newCustomLogger(prefix) +} diff --git a/runtime_window.go b/runtime_window.go new file mode 100644 index 000000000..813009bff --- /dev/null +++ b/runtime_window.go @@ -0,0 +1,32 @@ +package wails + +type RuntimeWindow struct { + renderer Renderer +} + +func newRuntimeWindow(renderer Renderer) *RuntimeWindow { + return &RuntimeWindow{ + renderer: renderer, + } +} + +func (r *RuntimeWindow) SetColour(colour string) error { + return r.renderer.SetColour(colour) +} + +func (r *RuntimeWindow) Fullscreen() { + r.renderer.Fullscreen() +} + +func (r *RuntimeWindow) UnFullscreen() { + r.renderer.UnFullscreen() +} + +func (r *RuntimeWindow) SetTitle(title string) { + r.renderer.SetTitle(title) +} + +func (r *RuntimeWindow) Close() { + // TODO: Add shutdown mechanism + r.renderer.Close() +} diff --git a/utils.go b/utils.go new file mode 100644 index 000000000..4ce362737 --- /dev/null +++ b/utils.go @@ -0,0 +1,12 @@ +package wails + +import ( + "strings" +) + +func escapeJS(js string) (string, error) { + result := strings.Replace(js, "\\", "\\\\", -1) + result = strings.Replace(result, "'", "\\'", -1) + result = strings.Replace(result, "\n", "\\n", -1) + return result, nil +} diff --git a/webview/webview.go b/webview/webview.go new file mode 100644 index 000000000..2ae4ef422 --- /dev/null +++ b/webview/webview.go @@ -0,0 +1,372 @@ +// Package wails implements Go bindings to https://github.com/zserge/webview C library. +// It is a modified version of webview.go from that repository + +// Bindings closely repeat the C APIs and include both, a simplified +// single-function API to just open a full-screen webview window, and a more +// advanced and featureful set of APIs, including Go-to-JavaScript bindings. +// +// The library uses gtk-webkit, Cocoa/Webkit and MSHTML (IE8..11) as a browser +// engine and supports Linux, MacOS and Windows 7..10 respectively. +// +package webview + +/* +#cgo linux openbsd freebsd CFLAGS: -DWEBVIEW_GTK=1 +#cgo linux openbsd freebsd pkg-config: gtk+-3.0 webkit2gtk-4.0 + +#cgo windows CFLAGS: -DWEBVIEW_WINAPI=1 +#cgo windows LDFLAGS: -lole32 -lcomctl32 -loleaut32 -luuid -lgdi32 + +#cgo darwin CFLAGS: -DWEBVIEW_COCOA=1 -x objective-c +#cgo darwin LDFLAGS: -framework Cocoa -framework WebKit + +#include +#include +#define WEBVIEW_STATIC +#define WEBVIEW_IMPLEMENTATION +#include "webview.h" + +extern void _webviewExternalInvokeCallback(void *, void *); + +static inline void CgoWebViewFree(void *w) { + free((void *)((struct webview *)w)->title); + free((void *)((struct webview *)w)->url); + free(w); +} + +static inline void *CgoWebViewCreate(int width, int height, char *title, char *url, int resizable, int debug) { + struct webview *w = (struct webview *) calloc(1, sizeof(*w)); + w->width = width; + w->height = height; + w->title = title; + w->url = url; + w->resizable = resizable; + w->debug = debug; + w->external_invoke_cb = (webview_external_invoke_cb_t) _webviewExternalInvokeCallback; + if (webview_init(w) != 0) { + CgoWebViewFree(w); + return NULL; + } + return (void *)w; +} + +static inline int CgoWebViewLoop(void *w, int blocking) { + return webview_loop((struct webview *)w, blocking); +} + +static inline void CgoWebViewTerminate(void *w) { + webview_terminate((struct webview *)w); +} + +static inline void CgoWebViewExit(void *w) { + webview_exit((struct webview *)w); +} + +static inline void CgoWebViewSetTitle(void *w, char *title) { + webview_set_title((struct webview *)w, title); +} + +static inline void CgoWebViewSetFullscreen(void *w, int fullscreen) { + webview_set_fullscreen((struct webview *)w, fullscreen); +} + +static inline void CgoWebViewSetColor(void *w, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + webview_set_color((struct webview *)w, r, g, b, a); +} + +static inline void CgoDialog(void *w, int dlgtype, int flags, + char *title, char *arg, char *res, size_t ressz) { + webview_dialog(w, dlgtype, flags, + (const char*)title, (const char*) arg, res, ressz); +} + +static inline int CgoWebViewEval(void *w, char *js) { + return webview_eval((struct webview *)w, js); +} + +static inline void CgoWebViewInjectCSS(void *w, char *css) { + webview_inject_css((struct webview *)w, css); +} + +extern void _webviewDispatchGoCallback(void *); +static inline void _webview_dispatch_cb(struct webview *w, void *arg) { + _webviewDispatchGoCallback(arg); +} +static inline void CgoWebViewDispatch(void *w, uintptr_t arg) { + webview_dispatch((struct webview *)w, _webview_dispatch_cb, (void *)arg); +} +*/ +import "C" +import ( + "errors" + "runtime" + "sync" + "unsafe" +) + +func init() { + // Ensure that main.main is called from the main thread + runtime.LockOSThread() +} + +// Open is a simplified API to open a single native window with a full-size webview in +// it. It can be helpful if you want to communicate with the core app using XHR +// or WebSockets (as opposed to using JavaScript bindings). +// +// Window appearance can be customized using title, width, height and resizable parameters. +// URL must be provided and can user either a http or https protocol, or be a +// local file:// URL. On some platforms "data:" URLs are also supported +// (Linux/MacOS). +func Open(title, url string, w, h int, resizable bool) error { + titleStr := C.CString(title) + defer C.free(unsafe.Pointer(titleStr)) + urlStr := C.CString(url) + defer C.free(unsafe.Pointer(urlStr)) + resize := C.int(0) + if resizable { + resize = C.int(1) + } + + r := C.webview(titleStr, urlStr, C.int(w), C.int(h), resize) + if r != 0 { + return errors.New("failed to create webview") + } + return nil +} + +// ExternalInvokeCallbackFunc is a function type that is called every time +// "window.external.invoke()" is called from JavaScript. Data is the only +// obligatory string parameter passed into the "invoke(data)" function from +// JavaScript. To pass more complex data serialized JSON or base64 encoded +// string can be used. +type ExternalInvokeCallbackFunc func(w WebView, data string) + +// Settings is a set of parameters to customize the initial WebView appearance +// and behavior. It is passed into the webview.New() constructor. +type Settings struct { + // WebView main window title + Title string + // URL to open in a webview + URL string + // Window width in pixels + Width int + // Window height in pixels + Height int + // Allows/disallows window resizing + Resizable bool + // Enable debugging tools (Linux/BSD/MacOS, on Windows use Firebug) + Debug bool + // A callback that is executed when JavaScript calls "window.external.invoke()" + ExternalInvokeCallback ExternalInvokeCallbackFunc +} + +// WebView is an interface that wraps the basic methods for controlling the UI +// loop, handling multithreading and providing JavaScript bindings. +type WebView interface { + // Run() starts the main UI loop until the user closes the webview window or + // Terminate() is called. + Run() + // Loop() runs a single iteration of the main UI. + Loop(blocking bool) bool + // SetTitle() changes window title. This method must be called from the main + // thread only. See Dispatch() for more details. + SetTitle(title string) + // SetFullscreen() controls window full-screen mode. This method must be + // called from the main thread only. See Dispatch() for more details. + SetFullscreen(fullscreen bool) + // SetColor() changes window background color. This method must be called from + // the main thread only. See Dispatch() for more details. + SetColor(r, g, b, a uint8) + // Eval() evaluates an arbitrary JS code inside the webview. This method must + // be called from the main thread only. See Dispatch() for more details. + Eval(js string) error + // InjectJS() injects an arbitrary block of CSS code using the JS API. This + // method must be called from the main thread only. See Dispatch() for more + // details. + InjectCSS(css string) + // Dialog() opens a system dialog of the given type and title. String + // argument can be provided for certain dialogs, such as alert boxes. For + // alert boxes argument is a message inside the dialog box. + Dialog(dlgType DialogType, flags int, title string, arg string) string + // Terminate() breaks the main UI loop. This method must be called from the main thread + // only. See Dispatch() for more details. + Terminate() + // Dispatch() schedules some arbitrary function to be executed on the main UI + // thread. This may be helpful if you want to run some JavaScript from + // background threads/goroutines, or to terminate the app. + Dispatch(func()) + // Exit() closes the window and cleans up the resources. Use Terminate() to + // forcefully break out of the main UI loop. + Exit() +} + +// DialogType is an enumeration of all supported system dialog types +type DialogType int + +const ( + // DialogTypeOpen is a system file open dialog + DialogTypeOpen DialogType = iota + // DialogTypeSave is a system file save dialog + DialogTypeSave + // DialogTypeAlert is a system alert dialog (message box) + DialogTypeAlert +) + +const ( + // DialogFlagFile is a normal file picker dialog + DialogFlagFile = C.WEBVIEW_DIALOG_FLAG_FILE + // DialogFlagDirectory is an open directory dialog + DialogFlagDirectory = C.WEBVIEW_DIALOG_FLAG_DIRECTORY + // DialogFlagInfo is an info alert dialog + DialogFlagInfo = C.WEBVIEW_DIALOG_FLAG_INFO + // DialogFlagWarning is a warning alert dialog + DialogFlagWarning = C.WEBVIEW_DIALOG_FLAG_WARNING + // DialogFlagError is an error dialog + DialogFlagError = C.WEBVIEW_DIALOG_FLAG_ERROR +) + +var ( + m sync.Mutex + index uintptr + fns = map[uintptr]func(){} + cbs = map[WebView]ExternalInvokeCallbackFunc{} +) + +type webview struct { + w unsafe.Pointer +} + +var _ WebView = &webview{} + +func boolToInt(b bool) int { + if b { + return 1 + } + return 0 +} + +// NewWebview creates and opens a new webview window using the given settings. The +// returned object implements the WebView interface. This function returns nil +// if a window can not be created. +func NewWebview(settings Settings) WebView { + if settings.Width == 0 { + settings.Width = 640 + } + if settings.Height == 0 { + settings.Height = 480 + } + if settings.Title == "" { + settings.Title = "WebView" + } + w := &webview{} + w.w = C.CgoWebViewCreate(C.int(settings.Width), C.int(settings.Height), + C.CString(settings.Title), C.CString(settings.URL), + C.int(boolToInt(settings.Resizable)), C.int(boolToInt(settings.Debug))) + m.Lock() + if settings.ExternalInvokeCallback != nil { + cbs[w] = settings.ExternalInvokeCallback + } else { + cbs[w] = func(w WebView, data string) {} + } + m.Unlock() + return w +} + +func (w *webview) Loop(blocking bool) bool { + block := C.int(0) + if blocking { + block = 1 + } + return C.CgoWebViewLoop(w.w, block) == 0 +} + +func (w *webview) Run() { + for w.Loop(true) { + } +} + +func (w *webview) Exit() { + C.CgoWebViewExit(w.w) +} + +func (w *webview) Dispatch(f func()) { + m.Lock() + for ; fns[index] != nil; index++ { + } + fns[index] = f + m.Unlock() + C.CgoWebViewDispatch(w.w, C.uintptr_t(index)) +} + +func (w *webview) SetTitle(title string) { + p := C.CString(title) + defer C.free(unsafe.Pointer(p)) + C.CgoWebViewSetTitle(w.w, p) +} + +func (w *webview) SetColor(r, g, b, a uint8) { + C.CgoWebViewSetColor(w.w, C.uint8_t(r), C.uint8_t(g), C.uint8_t(b), C.uint8_t(a)) +} + +func (w *webview) SetFullscreen(fullscreen bool) { + C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen))) +} + +func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string) string { + const maxPath = 4096 + titlePtr := C.CString(title) + defer C.free(unsafe.Pointer(titlePtr)) + argPtr := C.CString(arg) + defer C.free(unsafe.Pointer(argPtr)) + resultPtr := (*C.char)(C.calloc((C.size_t)(unsafe.Sizeof((*C.char)(nil))), (C.size_t)(maxPath))) + defer C.free(unsafe.Pointer(resultPtr)) + C.CgoDialog(w.w, C.int(dlgType), C.int(flags), titlePtr, + argPtr, resultPtr, C.size_t(maxPath)) + return C.GoString(resultPtr) +} + +func (w *webview) Eval(js string) error { + p := C.CString(js) + defer C.free(unsafe.Pointer(p)) + switch C.CgoWebViewEval(w.w, p) { + case -1: + return errors.New("evaluation failed") + } + return nil +} + +func (w *webview) InjectCSS(css string) { + p := C.CString(css) + defer C.free(unsafe.Pointer(p)) + C.CgoWebViewInjectCSS(w.w, p) +} + +func (w *webview) Terminate() { + C.CgoWebViewTerminate(w.w) +} + +//export _webviewDispatchGoCallback +func _webviewDispatchGoCallback(index unsafe.Pointer) { + var f func() + m.Lock() + f = fns[uintptr(index)] + delete(fns, uintptr(index)) + m.Unlock() + f() +} + +//export _webviewExternalInvokeCallback +func _webviewExternalInvokeCallback(w unsafe.Pointer, data unsafe.Pointer) { + m.Lock() + var ( + cb ExternalInvokeCallbackFunc + wv WebView + ) + for wv, cb = range cbs { + if wv.(*webview).w == w { + break + } + } + m.Unlock() + cb(wv, C.GoString((*C.char)(data))) +} diff --git a/webview/webview.h b/webview/webview.h new file mode 100644 index 000000000..78b0bcf6f --- /dev/null +++ b/webview/webview.h @@ -0,0 +1,1927 @@ +/* + * MIT License + * + * Copyright (c) 2017 Serge Zaitsev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef WEBVIEW_H +#define WEBVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WEBVIEW_STATIC +#define WEBVIEW_API static +#else +#define WEBVIEW_API extern +#endif + +#include +#include +#include + +#if defined(WEBVIEW_GTK) +#include +#include +#include + +struct webview_priv { + GtkWidget *window; + GtkWidget *scroller; + GtkWidget *webview; + GtkWidget *inspector_window; + GAsyncQueue *queue; + int ready; + int js_busy; + int should_exit; +}; +#elif defined(WEBVIEW_WINAPI) +#define CINTERFACE +#include + +#include +#include +#include +#include +#include + +#include + +struct webview_priv { + HWND hwnd; + IOleObject **browser; + BOOL is_fullscreen; + DWORD saved_style; + DWORD saved_ex_style; + RECT saved_rect; +}; +#elif defined(WEBVIEW_COCOA) +#import +#import +#import + +struct webview_priv { + NSAutoreleasePool *pool; + NSWindow *window; + WebView *webview; + id windowDelegate; + int should_exit; +}; +#else +#error "Define one of: WEBVIEW_GTK, WEBVIEW_COCOA or WEBVIEW_WINAPI" +#endif + +struct webview; + +typedef void (*webview_external_invoke_cb_t)(struct webview *w, + const char *arg); + +struct webview { + const char *url; + const char *title; + int width; + int height; + int resizable; + int transparentTitlebar; + int debug; + webview_external_invoke_cb_t external_invoke_cb; + struct webview_priv priv; + void *userdata; +}; + +enum webview_dialog_type { + WEBVIEW_DIALOG_TYPE_OPEN = 0, + WEBVIEW_DIALOG_TYPE_SAVE = 1, + WEBVIEW_DIALOG_TYPE_ALERT = 2 +}; + +#define WEBVIEW_DIALOG_FLAG_FILE (0 << 0) +#define WEBVIEW_DIALOG_FLAG_DIRECTORY (1 << 0) + +#define WEBVIEW_DIALOG_FLAG_INFO (1 << 1) +#define WEBVIEW_DIALOG_FLAG_WARNING (2 << 1) +#define WEBVIEW_DIALOG_FLAG_ERROR (3 << 1) +#define WEBVIEW_DIALOG_FLAG_ALERT_MASK (3 << 1) + +typedef void (*webview_dispatch_fn)(struct webview *w, void *arg); + +struct webview_dispatch_arg { + webview_dispatch_fn fn; + struct webview *w; + void *arg; +}; + +#define DEFAULT_URL \ + "data:text/" \ + "html,%3C%21DOCTYPE%20html%3E%0A%3Chtml%20lang=%22en%22%3E%0A%3Chead%3E%" \ + "3Cmeta%20charset=%22utf-8%22%3E%3Cmeta%20http-equiv=%22X-UA-Compatible%22%" \ + "20content=%22IE=edge%22%3E%3C%2Fhead%3E%0A%3Cbody%3E%3Cdiv%20id=%22app%22%" \ + "3E%3C%2Fdiv%3E%3Cscript%20type=%22text%2Fjavascript%22%3E%3C%2Fscript%3E%" \ + "3C%2Fbody%3E%0A%3C%2Fhtml%3E" + +#define CSS_INJECT_FUNCTION \ + "(function(e){var " \ + "t=document.createElement('style'),d=document.head||document." \ + "getElementsByTagName('head')[0];t.setAttribute('type','text/" \ + "css'),t.styleSheet?t.styleSheet.cssText=e:t.appendChild(document." \ + "createTextNode(e)),d.appendChild(t)})" + +static const char *webview_check_url(const char *url) { + if (url == NULL || strlen(url) == 0) { + return DEFAULT_URL; + } + return url; +} + +WEBVIEW_API int webview(const char *title, const char *url, int width, + int height, int resizable); + +WEBVIEW_API int webview_init(struct webview *w); +WEBVIEW_API int webview_loop(struct webview *w, int blocking); +WEBVIEW_API int webview_eval(struct webview *w, const char *js); +WEBVIEW_API int webview_inject_css(struct webview *w, const char *css); +WEBVIEW_API void webview_set_title(struct webview *w, const char *title); +WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen); +WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g, + uint8_t b, uint8_t a); +WEBVIEW_API void webview_dialog(struct webview *w, + enum webview_dialog_type dlgtype, int flags, + const char *title, const char *arg, + char *result, size_t resultsz); +WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn, + void *arg); +WEBVIEW_API void webview_terminate(struct webview *w); +WEBVIEW_API void webview_exit(struct webview *w); +WEBVIEW_API void webview_debug(const char *format, ...); +WEBVIEW_API void webview_print_log(const char *s); + +#ifdef WEBVIEW_IMPLEMENTATION +#undef WEBVIEW_IMPLEMENTATION + +WEBVIEW_API int webview(const char *title, const char *url, int width, + int height, int resizable) { + struct webview webview; + memset(&webview, 0, sizeof(webview)); + webview.title = title; + webview.url = url; + webview.width = width; + webview.height = height; + webview.resizable = resizable; + int r = webview_init(&webview); + if (r != 0) { + return r; + } + while (webview_loop(&webview, 1) == 0) { + } + webview_exit(&webview); + return 0; +} + +WEBVIEW_API void webview_debug(const char *format, ...) { + char buf[4096]; + va_list ap; + va_start(ap, format); + vsnprintf(buf, sizeof(buf), format, ap); + webview_print_log(buf); + va_end(ap); +} + +static int webview_js_encode(const char *s, char *esc, size_t n) { + int r = 1; /* At least one byte for trailing zero */ + for (; *s; s++) { + const unsigned char c = *s; + if (c >= 0x20 && c < 0x80 && strchr("<>\\'\"", c) == NULL) { + if (n > 0) { + *esc++ = c; + n--; + } + r++; + } else { + if (n > 0) { + snprintf(esc, n, "\\x%02x", (int)c); + esc += 4; + n -= 4; + } + r += 4; + } + } + return r; +} + +WEBVIEW_API int webview_inject_css(struct webview *w, const char *css) { + int n = webview_js_encode(css, NULL, 0); + char *esc = (char *)calloc(1, sizeof(CSS_INJECT_FUNCTION) + n + 4); + if (esc == NULL) { + return -1; + } + char *js = (char *)calloc(1, n); + webview_js_encode(css, js, n); + snprintf(esc, sizeof(CSS_INJECT_FUNCTION) + n + 4, "%s(\"%s\")", + CSS_INJECT_FUNCTION, js); + int r = webview_eval(w, esc); + free(js); + free(esc); + return r; +} + +#if defined(WEBVIEW_GTK) +static void external_message_received_cb(WebKitUserContentManager *m, + WebKitJavascriptResult *r, + gpointer arg) { + (void)m; + struct webview *w = (struct webview *)arg; + if (w->external_invoke_cb == NULL) { + return; + } + JSGlobalContextRef context = webkit_javascript_result_get_global_context(r); + JSValueRef value = webkit_javascript_result_get_value(r); + JSStringRef js = JSValueToStringCopy(context, value, NULL); + size_t n = JSStringGetMaximumUTF8CStringSize(js); + char *s = g_new(char, n); + JSStringGetUTF8CString(js, s, n); + w->external_invoke_cb(w, s); + JSStringRelease(js); + g_free(s); +} + +static void webview_load_changed_cb(WebKitWebView *webview, + WebKitLoadEvent event, gpointer arg) { + (void)webview; + struct webview *w = (struct webview *)arg; + if (event == WEBKIT_LOAD_FINISHED) { + w->priv.ready = 1; + } +} + +static void webview_destroy_cb(GtkWidget *widget, gpointer arg) { + (void)widget; + struct webview *w = (struct webview *)arg; + webview_terminate(w); +} + +static gboolean webview_context_menu_cb(WebKitWebView *webview, + GtkWidget *default_menu, + WebKitHitTestResult *hit_test_result, + gboolean triggered_with_keyboard, + gpointer userdata) { + (void)webview; + (void)default_menu; + (void)hit_test_result; + (void)triggered_with_keyboard; + (void)userdata; + return TRUE; +} + +WEBVIEW_API int webview_init(struct webview *w) { + if (gtk_init_check(0, NULL) == FALSE) { + return -1; + } + + w->priv.ready = 0; + w->priv.should_exit = 0; + w->priv.queue = g_async_queue_new(); + w->priv.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(w->priv.window), w->title); + + if (w->resizable) { + gtk_window_set_default_size(GTK_WINDOW(w->priv.window), w->width, + w->height); + } else { + gtk_widget_set_size_request(w->priv.window, w->width, w->height); + } + gtk_window_set_resizable(GTK_WINDOW(w->priv.window), !!w->resizable); + gtk_window_set_position(GTK_WINDOW(w->priv.window), GTK_WIN_POS_CENTER); + + w->priv.scroller = gtk_scrolled_window_new(NULL, NULL); + gtk_container_add(GTK_CONTAINER(w->priv.window), w->priv.scroller); + + WebKitUserContentManager *m = webkit_user_content_manager_new(); + webkit_user_content_manager_register_script_message_handler(m, "external"); + g_signal_connect(m, "script-message-received::external", + G_CALLBACK(external_message_received_cb), w); + + w->priv.webview = webkit_web_view_new_with_user_content_manager(m); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(w->priv.webview), + webview_check_url(w->url)); + g_signal_connect(G_OBJECT(w->priv.webview), "load-changed", + G_CALLBACK(webview_load_changed_cb), w); + gtk_container_add(GTK_CONTAINER(w->priv.scroller), w->priv.webview); + + if (w->debug) { + WebKitSettings *settings = + webkit_web_view_get_settings(WEBKIT_WEB_VIEW(w->priv.webview)); + webkit_settings_set_enable_write_console_messages_to_stdout(settings, true); + webkit_settings_set_enable_developer_extras(settings, true); + } else { + g_signal_connect(G_OBJECT(w->priv.webview), "context-menu", + G_CALLBACK(webview_context_menu_cb), w); + } + + gtk_widget_show_all(w->priv.window); + + webkit_web_view_run_javascript( + WEBKIT_WEB_VIEW(w->priv.webview), + "window.external={invoke:function(x){" + "window.webkit.messageHandlers.external.postMessage(x);}}", + NULL, NULL, NULL); + + g_signal_connect(G_OBJECT(w->priv.window), "destroy", + G_CALLBACK(webview_destroy_cb), w); + return 0; +} + +WEBVIEW_API int webview_loop(struct webview *w, int blocking) { + gtk_main_iteration_do(blocking); + return w->priv.should_exit; +} + +WEBVIEW_API void webview_set_title(struct webview *w, const char *title) { + gtk_window_set_title(GTK_WINDOW(w->priv.window), title); +} + +WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) { + if (fullscreen) { + gtk_window_fullscreen(GTK_WINDOW(w->priv.window)); + } else { + gtk_window_unfullscreen(GTK_WINDOW(w->priv.window)); + } +} + +WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g, + uint8_t b, uint8_t a) { + GdkRGBA color = {r / 255.0, g / 255.0, b / 255.0, a / 255.0}; + webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(w->priv.webview), + &color); +} + +WEBVIEW_API void webview_dialog(struct webview *w, + enum webview_dialog_type dlgtype, int flags, + const char *title, const char *arg, + char *result, size_t resultsz) { + GtkWidget *dlg; + if (result != NULL) { + result[0] = '\0'; + } + if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN || + dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) { + dlg = gtk_file_chooser_dialog_new( + title, GTK_WINDOW(w->priv.window), + (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN + ? (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY + ? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER + : GTK_FILE_CHOOSER_ACTION_OPEN) + : GTK_FILE_CHOOSER_ACTION_SAVE), + "_Cancel", GTK_RESPONSE_CANCEL, + (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ? "_Open" : "_Save"), + GTK_RESPONSE_ACCEPT, NULL); + gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE); + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE); + gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE); + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dlg), TRUE); + gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dlg), TRUE); + gint response = gtk_dialog_run(GTK_DIALOG(dlg)); + if (response == GTK_RESPONSE_ACCEPT) { + gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg)); + g_strlcpy(result, filename, resultsz); + g_free(filename); + } + gtk_widget_destroy(dlg); + } else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) { + GtkMessageType type = GTK_MESSAGE_OTHER; + switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) { + case WEBVIEW_DIALOG_FLAG_INFO: + type = GTK_MESSAGE_INFO; + break; + case WEBVIEW_DIALOG_FLAG_WARNING: + type = GTK_MESSAGE_WARNING; + break; + case WEBVIEW_DIALOG_FLAG_ERROR: + type = GTK_MESSAGE_ERROR; + break; + } + dlg = gtk_message_dialog_new(GTK_WINDOW(w->priv.window), GTK_DIALOG_MODAL, + type, GTK_BUTTONS_OK, "%s", title); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dlg), "%s", + arg); + gtk_dialog_run(GTK_DIALOG(dlg)); + gtk_widget_destroy(dlg); + } +} + +static void webview_eval_finished(GObject *object, GAsyncResult *result, + gpointer userdata) { + (void) object; + (void) result; + struct webview *w = (struct webview *)userdata; + w->priv.js_busy = 0; +} + +WEBVIEW_API int webview_eval(struct webview *w, const char *js) { + while (w->priv.ready == 0) { + g_main_context_iteration(NULL, TRUE); + } + w->priv.js_busy = 1; + webkit_web_view_run_javascript(WEBKIT_WEB_VIEW(w->priv.webview), js, NULL, + webview_eval_finished, w); + while (w->priv.js_busy) { + g_main_context_iteration(NULL, TRUE); + } + return 0; +} + +static gboolean webview_dispatch_wrapper(gpointer userdata) { + struct webview *w = (struct webview *)userdata; + for (;;) { + struct webview_dispatch_arg *arg = + (struct webview_dispatch_arg *)g_async_queue_try_pop(w->priv.queue); + if (arg == NULL) { + break; + } + (arg->fn)(w, arg->arg); + g_free(arg); + } + return FALSE; +} + +WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn, + void *arg) { + struct webview_dispatch_arg *context = + (struct webview_dispatch_arg *)g_new(struct webview_dispatch_arg *, 1); + context->w = w; + context->arg = arg; + context->fn = fn; + g_async_queue_lock(w->priv.queue); + g_async_queue_push_unlocked(w->priv.queue, context); + if (g_async_queue_length_unlocked(w->priv.queue) == 1) { + gdk_threads_add_idle(webview_dispatch_wrapper, w); + } + g_async_queue_unlock(w->priv.queue); +} + +WEBVIEW_API void webview_terminate(struct webview *w) { + w->priv.should_exit = 1; +} + +WEBVIEW_API void webview_exit(struct webview *w) { (void)w; } +WEBVIEW_API void webview_print_log(const char *s) { + fprintf(stderr, "%s\n", s); +} + +#endif /* WEBVIEW_GTK */ + +#if defined(WEBVIEW_WINAPI) + +#pragma comment(lib, "user32.lib") +#pragma comment(lib, "ole32.lib") +#pragma comment(lib, "oleaut32.lib") + +#define WM_WEBVIEW_DISPATCH (WM_APP + 1) + +typedef struct { + IOleInPlaceFrame frame; + HWND window; +} _IOleInPlaceFrameEx; + +typedef struct { + IOleInPlaceSite inplace; + _IOleInPlaceFrameEx frame; +} _IOleInPlaceSiteEx; + +typedef struct { IDocHostUIHandler ui; } _IDocHostUIHandlerEx; + +typedef struct { + IOleClientSite client; + _IOleInPlaceSiteEx inplace; + _IDocHostUIHandlerEx ui; + IDispatch external; +} _IOleClientSiteEx; + +#ifdef __cplusplus +#define iid_ref(x) &(x) +#define iid_unref(x) *(x) +#else +#define iid_ref(x) (x) +#define iid_unref(x) (x) +#endif + +static inline WCHAR *webview_to_utf16(const char *s) { + DWORD size = MultiByteToWideChar(CP_UTF8, 0, s, -1, 0, 0); + WCHAR *ws = (WCHAR *)GlobalAlloc(GMEM_FIXED, sizeof(WCHAR) * size); + if (ws == NULL) { + return NULL; + } + MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, size); + return ws; +} + +static inline char *webview_from_utf16(WCHAR *ws) { + int n = WideCharToMultiByte(CP_UTF8, 0, ws, -1, NULL, 0, NULL, NULL); + char *s = (char *)GlobalAlloc(GMEM_FIXED, n); + if (s == NULL) { + return NULL; + } + WideCharToMultiByte(CP_UTF8, 0, ws, -1, s, n, NULL, NULL); + return s; +} + +static int iid_eq(REFIID a, const IID *b) { + return memcmp((const void *)iid_ref(a), (const void *)b, sizeof(GUID)) == 0; +} + +static HRESULT STDMETHODCALLTYPE JS_QueryInterface(IDispatch FAR *This, + REFIID riid, + LPVOID FAR *ppvObj) { + if (iid_eq(riid, &IID_IDispatch)) { + *ppvObj = This; + return S_OK; + } + *ppvObj = 0; + return E_NOINTERFACE; +} +static ULONG STDMETHODCALLTYPE JS_AddRef(IDispatch FAR *This) { return 1; } +static ULONG STDMETHODCALLTYPE JS_Release(IDispatch FAR *This) { return 1; } +static HRESULT STDMETHODCALLTYPE JS_GetTypeInfoCount(IDispatch FAR *This, + UINT *pctinfo) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE JS_GetTypeInfo(IDispatch FAR *This, + UINT iTInfo, LCID lcid, + ITypeInfo **ppTInfo) { + return S_OK; +} +#define WEBVIEW_JS_INVOKE_ID 0x1000 +static HRESULT STDMETHODCALLTYPE JS_GetIDsOfNames(IDispatch FAR *This, + REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, LCID lcid, + DISPID *rgDispId) { + if (cNames != 1) { + return S_FALSE; + } + if (wcscmp(rgszNames[0], L"invoke") == 0) { + rgDispId[0] = WEBVIEW_JS_INVOKE_ID; + return S_OK; + } + return S_FALSE; +} + +static HRESULT STDMETHODCALLTYPE +JS_Invoke(IDispatch FAR *This, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) { + size_t offset = (size_t) & ((_IOleClientSiteEx *)NULL)->external; + _IOleClientSiteEx *ex = (_IOleClientSiteEx *)((char *)(This)-offset); + struct webview *w = (struct webview *)GetWindowLongPtr( + ex->inplace.frame.window, GWLP_USERDATA); + if (pDispParams->cArgs == 1 && pDispParams->rgvarg[0].vt == VT_BSTR) { + BSTR bstr = pDispParams->rgvarg[0].bstrVal; + char *s = webview_from_utf16(bstr); + if (s != NULL) { + if (dispIdMember == WEBVIEW_JS_INVOKE_ID) { + if (w->external_invoke_cb != NULL) { + w->external_invoke_cb(w, s); + } + } else { + return S_FALSE; + } + GlobalFree(s); + } + } + return S_OK; +} + +static IDispatchVtbl ExternalDispatchTable = { + JS_QueryInterface, JS_AddRef, JS_Release, JS_GetTypeInfoCount, + JS_GetTypeInfo, JS_GetIDsOfNames, JS_Invoke}; + +static ULONG STDMETHODCALLTYPE Site_AddRef(IOleClientSite FAR *This) { + return 1; +} +static ULONG STDMETHODCALLTYPE Site_Release(IOleClientSite FAR *This) { + return 1; +} +static HRESULT STDMETHODCALLTYPE Site_SaveObject(IOleClientSite FAR *This) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE Site_GetMoniker(IOleClientSite FAR *This, + DWORD dwAssign, + DWORD dwWhichMoniker, + IMoniker **ppmk) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE +Site_GetContainer(IOleClientSite FAR *This, LPOLECONTAINER FAR *ppContainer) { + *ppContainer = 0; + return E_NOINTERFACE; +} +static HRESULT STDMETHODCALLTYPE Site_ShowObject(IOleClientSite FAR *This) { + return NOERROR; +} +static HRESULT STDMETHODCALLTYPE Site_OnShowWindow(IOleClientSite FAR *This, + BOOL fShow) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE +Site_RequestNewObjectLayout(IOleClientSite FAR *This) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE Site_QueryInterface(IOleClientSite FAR *This, + REFIID riid, + void **ppvObject) { + if (iid_eq(riid, &IID_IUnknown) || iid_eq(riid, &IID_IOleClientSite)) { + *ppvObject = &((_IOleClientSiteEx *)This)->client; + } else if (iid_eq(riid, &IID_IOleInPlaceSite)) { + *ppvObject = &((_IOleClientSiteEx *)This)->inplace; + } else if (iid_eq(riid, &IID_IDocHostUIHandler)) { + *ppvObject = &((_IOleClientSiteEx *)This)->ui; + } else { + *ppvObject = 0; + return (E_NOINTERFACE); + } + return S_OK; +} +static HRESULT STDMETHODCALLTYPE InPlace_QueryInterface( + IOleInPlaceSite FAR *This, REFIID riid, LPVOID FAR *ppvObj) { + return (Site_QueryInterface( + (IOleClientSite *)((char *)This - sizeof(IOleClientSite)), riid, ppvObj)); +} +static ULONG STDMETHODCALLTYPE InPlace_AddRef(IOleInPlaceSite FAR *This) { + return 1; +} +static ULONG STDMETHODCALLTYPE InPlace_Release(IOleInPlaceSite FAR *This) { + return 1; +} +static HRESULT STDMETHODCALLTYPE InPlace_GetWindow(IOleInPlaceSite FAR *This, + HWND FAR *lphwnd) { + *lphwnd = ((_IOleInPlaceSiteEx FAR *)This)->frame.window; + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +InPlace_ContextSensitiveHelp(IOleInPlaceSite FAR *This, BOOL fEnterMode) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE +InPlace_CanInPlaceActivate(IOleInPlaceSite FAR *This) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +InPlace_OnInPlaceActivate(IOleInPlaceSite FAR *This) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +InPlace_OnUIActivate(IOleInPlaceSite FAR *This) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE InPlace_GetWindowContext( + IOleInPlaceSite FAR *This, LPOLEINPLACEFRAME FAR *lplpFrame, + LPOLEINPLACEUIWINDOW FAR *lplpDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, + LPOLEINPLACEFRAMEINFO lpFrameInfo) { + *lplpFrame = (LPOLEINPLACEFRAME) & ((_IOleInPlaceSiteEx *)This)->frame; + *lplpDoc = 0; + lpFrameInfo->fMDIApp = FALSE; + lpFrameInfo->hwndFrame = ((_IOleInPlaceFrameEx *)*lplpFrame)->window; + lpFrameInfo->haccel = 0; + lpFrameInfo->cAccelEntries = 0; + return S_OK; +} +static HRESULT STDMETHODCALLTYPE InPlace_Scroll(IOleInPlaceSite FAR *This, + SIZE scrollExtent) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE +InPlace_OnUIDeactivate(IOleInPlaceSite FAR *This, BOOL fUndoable) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +InPlace_OnInPlaceDeactivate(IOleInPlaceSite FAR *This) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +InPlace_DiscardUndoState(IOleInPlaceSite FAR *This) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE +InPlace_DeactivateAndUndo(IOleInPlaceSite FAR *This) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE +InPlace_OnPosRectChange(IOleInPlaceSite FAR *This, LPCRECT lprcPosRect) { + IOleObject *browserObject; + IOleInPlaceObject *inplace; + browserObject = *((IOleObject **)((char *)This - sizeof(IOleObject *) - + sizeof(IOleClientSite))); + if (!browserObject->lpVtbl->QueryInterface(browserObject, + iid_unref(&IID_IOleInPlaceObject), + (void **)&inplace)) { + inplace->lpVtbl->SetObjectRects(inplace, lprcPosRect, lprcPosRect); + inplace->lpVtbl->Release(inplace); + } + return S_OK; +} +static HRESULT STDMETHODCALLTYPE Frame_QueryInterface( + IOleInPlaceFrame FAR *This, REFIID riid, LPVOID FAR *ppvObj) { + return E_NOTIMPL; +} +static ULONG STDMETHODCALLTYPE Frame_AddRef(IOleInPlaceFrame FAR *This) { + return 1; +} +static ULONG STDMETHODCALLTYPE Frame_Release(IOleInPlaceFrame FAR *This) { + return 1; +} +static HRESULT STDMETHODCALLTYPE Frame_GetWindow(IOleInPlaceFrame FAR *This, + HWND FAR *lphwnd) { + *lphwnd = ((_IOleInPlaceFrameEx *)This)->window; + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +Frame_ContextSensitiveHelp(IOleInPlaceFrame FAR *This, BOOL fEnterMode) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE Frame_GetBorder(IOleInPlaceFrame FAR *This, + LPRECT lprectBorder) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE Frame_RequestBorderSpace( + IOleInPlaceFrame FAR *This, LPCBORDERWIDTHS pborderwidths) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE Frame_SetBorderSpace( + IOleInPlaceFrame FAR *This, LPCBORDERWIDTHS pborderwidths) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE Frame_SetActiveObject( + IOleInPlaceFrame FAR *This, IOleInPlaceActiveObject *pActiveObject, + LPCOLESTR pszObjName) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +Frame_InsertMenus(IOleInPlaceFrame FAR *This, HMENU hmenuShared, + LPOLEMENUGROUPWIDTHS lpMenuWidths) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE Frame_SetMenu(IOleInPlaceFrame FAR *This, + HMENU hmenuShared, + HOLEMENU holemenu, + HWND hwndActiveObject) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE Frame_RemoveMenus(IOleInPlaceFrame FAR *This, + HMENU hmenuShared) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE Frame_SetStatusText(IOleInPlaceFrame FAR *This, + LPCOLESTR pszStatusText) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +Frame_EnableModeless(IOleInPlaceFrame FAR *This, BOOL fEnable) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +Frame_TranslateAccelerator(IOleInPlaceFrame FAR *This, LPMSG lpmsg, WORD wID) { + return E_NOTIMPL; +} +static HRESULT STDMETHODCALLTYPE UI_QueryInterface(IDocHostUIHandler FAR *This, + REFIID riid, + LPVOID FAR *ppvObj) { + return (Site_QueryInterface((IOleClientSite *)((char *)This - + sizeof(IOleClientSite) - + sizeof(_IOleInPlaceSiteEx)), + riid, ppvObj)); +} +static ULONG STDMETHODCALLTYPE UI_AddRef(IDocHostUIHandler FAR *This) { + return 1; +} +static ULONG STDMETHODCALLTYPE UI_Release(IDocHostUIHandler FAR *This) { + return 1; +} +static HRESULT STDMETHODCALLTYPE UI_ShowContextMenu( + IDocHostUIHandler FAR *This, DWORD dwID, POINT __RPC_FAR *ppt, + IUnknown __RPC_FAR *pcmdtReserved, IDispatch __RPC_FAR *pdispReserved) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +UI_GetHostInfo(IDocHostUIHandler FAR *This, DOCHOSTUIINFO __RPC_FAR *pInfo) { + pInfo->cbSize = sizeof(DOCHOSTUIINFO); + pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER; + pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT; + return S_OK; +} +static HRESULT STDMETHODCALLTYPE UI_ShowUI( + IDocHostUIHandler FAR *This, DWORD dwID, + IOleInPlaceActiveObject __RPC_FAR *pActiveObject, + IOleCommandTarget __RPC_FAR *pCommandTarget, + IOleInPlaceFrame __RPC_FAR *pFrame, IOleInPlaceUIWindow __RPC_FAR *pDoc) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE UI_HideUI(IDocHostUIHandler FAR *This) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE UI_UpdateUI(IDocHostUIHandler FAR *This) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE UI_EnableModeless(IDocHostUIHandler FAR *This, + BOOL fEnable) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +UI_OnDocWindowActivate(IDocHostUIHandler FAR *This, BOOL fActivate) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +UI_OnFrameWindowActivate(IDocHostUIHandler FAR *This, BOOL fActivate) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +UI_ResizeBorder(IDocHostUIHandler FAR *This, LPCRECT prcBorder, + IOleInPlaceUIWindow __RPC_FAR *pUIWindow, BOOL fRameWindow) { + return S_OK; +} +static HRESULT STDMETHODCALLTYPE +UI_TranslateAccelerator(IDocHostUIHandler FAR *This, LPMSG lpMsg, + const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID) { + return S_FALSE; +} +static HRESULT STDMETHODCALLTYPE UI_GetOptionKeyPath( + IDocHostUIHandler FAR *This, LPOLESTR __RPC_FAR *pchKey, DWORD dw) { + return S_FALSE; +} +static HRESULT STDMETHODCALLTYPE UI_GetDropTarget( + IDocHostUIHandler FAR *This, IDropTarget __RPC_FAR *pDropTarget, + IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget) { + return S_FALSE; +} +static HRESULT STDMETHODCALLTYPE UI_GetExternal( + IDocHostUIHandler FAR *This, IDispatch __RPC_FAR *__RPC_FAR *ppDispatch) { + *ppDispatch = (IDispatch *)(This + 1); + return S_OK; +} +static HRESULT STDMETHODCALLTYPE UI_TranslateUrl( + IDocHostUIHandler FAR *This, DWORD dwTranslate, OLECHAR __RPC_FAR *pchURLIn, + OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut) { + *ppchURLOut = 0; + return S_FALSE; +} +static HRESULT STDMETHODCALLTYPE +UI_FilterDataObject(IDocHostUIHandler FAR *This, IDataObject __RPC_FAR *pDO, + IDataObject __RPC_FAR *__RPC_FAR *ppDORet) { + *ppDORet = 0; + return S_FALSE; +} + +static const TCHAR *classname = "WebView"; +static const SAFEARRAYBOUND ArrayBound = {1, 0}; + +static IOleClientSiteVtbl MyIOleClientSiteTable = { + Site_QueryInterface, Site_AddRef, Site_Release, + Site_SaveObject, Site_GetMoniker, Site_GetContainer, + Site_ShowObject, Site_OnShowWindow, Site_RequestNewObjectLayout}; +static IOleInPlaceSiteVtbl MyIOleInPlaceSiteTable = { + InPlace_QueryInterface, + InPlace_AddRef, + InPlace_Release, + InPlace_GetWindow, + InPlace_ContextSensitiveHelp, + InPlace_CanInPlaceActivate, + InPlace_OnInPlaceActivate, + InPlace_OnUIActivate, + InPlace_GetWindowContext, + InPlace_Scroll, + InPlace_OnUIDeactivate, + InPlace_OnInPlaceDeactivate, + InPlace_DiscardUndoState, + InPlace_DeactivateAndUndo, + InPlace_OnPosRectChange}; + +static IOleInPlaceFrameVtbl MyIOleInPlaceFrameTable = { + Frame_QueryInterface, + Frame_AddRef, + Frame_Release, + Frame_GetWindow, + Frame_ContextSensitiveHelp, + Frame_GetBorder, + Frame_RequestBorderSpace, + Frame_SetBorderSpace, + Frame_SetActiveObject, + Frame_InsertMenus, + Frame_SetMenu, + Frame_RemoveMenus, + Frame_SetStatusText, + Frame_EnableModeless, + Frame_TranslateAccelerator}; + +static IDocHostUIHandlerVtbl MyIDocHostUIHandlerTable = { + UI_QueryInterface, + UI_AddRef, + UI_Release, + UI_ShowContextMenu, + UI_GetHostInfo, + UI_ShowUI, + UI_HideUI, + UI_UpdateUI, + UI_EnableModeless, + UI_OnDocWindowActivate, + UI_OnFrameWindowActivate, + UI_ResizeBorder, + UI_TranslateAccelerator, + UI_GetOptionKeyPath, + UI_GetDropTarget, + UI_GetExternal, + UI_TranslateUrl, + UI_FilterDataObject}; + +static void UnEmbedBrowserObject(struct webview *w) { + if (w->priv.browser != NULL) { + (*w->priv.browser)->lpVtbl->Close(*w->priv.browser, OLECLOSE_NOSAVE); + (*w->priv.browser)->lpVtbl->Release(*w->priv.browser); + GlobalFree(w->priv.browser); + w->priv.browser = NULL; + } +} + +static int EmbedBrowserObject(struct webview *w) { + RECT rect; + IWebBrowser2 *webBrowser2 = NULL; + LPCLASSFACTORY pClassFactory = NULL; + _IOleClientSiteEx *_iOleClientSiteEx = NULL; + IOleObject **browser = (IOleObject **)GlobalAlloc( + GMEM_FIXED, sizeof(IOleObject *) + sizeof(_IOleClientSiteEx)); + if (browser == NULL) { + goto error; + } + w->priv.browser = browser; + + _iOleClientSiteEx = (_IOleClientSiteEx *)(browser + 1); + _iOleClientSiteEx->client.lpVtbl = &MyIOleClientSiteTable; + _iOleClientSiteEx->inplace.inplace.lpVtbl = &MyIOleInPlaceSiteTable; + _iOleClientSiteEx->inplace.frame.frame.lpVtbl = &MyIOleInPlaceFrameTable; + _iOleClientSiteEx->inplace.frame.window = w->priv.hwnd; + _iOleClientSiteEx->ui.ui.lpVtbl = &MyIDocHostUIHandlerTable; + _iOleClientSiteEx->external.lpVtbl = &ExternalDispatchTable; + + if (CoGetClassObject(iid_unref(&CLSID_WebBrowser), + CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, NULL, + iid_unref(&IID_IClassFactory), + (void **)&pClassFactory) != S_OK) { + goto error; + } + + if (pClassFactory == NULL) { + goto error; + } + + if (pClassFactory->lpVtbl->CreateInstance(pClassFactory, 0, + iid_unref(&IID_IOleObject), + (void **)browser) != S_OK) { + goto error; + } + pClassFactory->lpVtbl->Release(pClassFactory); + if ((*browser)->lpVtbl->SetClientSite( + *browser, (IOleClientSite *)_iOleClientSiteEx) != S_OK) { + goto error; + } + (*browser)->lpVtbl->SetHostNames(*browser, L"My Host Name", 0); + + if (OleSetContainedObject((struct IUnknown *)(*browser), TRUE) != S_OK) { + goto error; + } + GetClientRect(w->priv.hwnd, &rect); + if ((*browser)->lpVtbl->DoVerb((*browser), OLEIVERB_SHOW, NULL, + (IOleClientSite *)_iOleClientSiteEx, -1, + w->priv.hwnd, &rect) != S_OK) { + goto error; + } + if ((*browser)->lpVtbl->QueryInterface((*browser), + iid_unref(&IID_IWebBrowser2), + (void **)&webBrowser2) != S_OK) { + goto error; + } + + webBrowser2->lpVtbl->put_Left(webBrowser2, 0); + webBrowser2->lpVtbl->put_Top(webBrowser2, 0); + webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right); + webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom); + webBrowser2->lpVtbl->Release(webBrowser2); + + return 0; +error: + UnEmbedBrowserObject(w); + if (pClassFactory != NULL) { + pClassFactory->lpVtbl->Release(pClassFactory); + } + if (browser != NULL) { + GlobalFree(browser); + } + return -1; +} + +#define WEBVIEW_DATA_URL_PREFIX "data:text/html," +static int DisplayHTMLPage(struct webview *w) { + IWebBrowser2 *webBrowser2; + VARIANT myURL; + LPDISPATCH lpDispatch; + IHTMLDocument2 *htmlDoc2; + BSTR bstr; + IOleObject *browserObject; + SAFEARRAY *sfArray; + VARIANT *pVar; + browserObject = *w->priv.browser; + int isDataURL = 0; + const char *webview_url = webview_check_url(w->url); + if (!browserObject->lpVtbl->QueryInterface( + browserObject, iid_unref(&IID_IWebBrowser2), (void **)&webBrowser2)) { + LPCSTR webPageName; + isDataURL = (strncmp(webview_url, WEBVIEW_DATA_URL_PREFIX, + strlen(WEBVIEW_DATA_URL_PREFIX)) == 0); + if (isDataURL) { + webPageName = "about:blank"; + } else { + webPageName = (LPCSTR)webview_url; + } + VariantInit(&myURL); + myURL.vt = VT_BSTR; +#ifndef UNICODE + { + wchar_t *buffer = webview_to_utf16(webPageName); + if (buffer == NULL) { + goto badalloc; + } + myURL.bstrVal = SysAllocString(buffer); + GlobalFree(buffer); + } +#else + myURL.bstrVal = SysAllocString(webPageName); +#endif + if (!myURL.bstrVal) { + badalloc: + webBrowser2->lpVtbl->Release(webBrowser2); + return (-6); + } + webBrowser2->lpVtbl->Navigate2(webBrowser2, &myURL, 0, 0, 0, 0); + VariantClear(&myURL); + if (!isDataURL) { + return 0; + } + + char *url = (char *)calloc(1, strlen(webview_url) + 1); + char *q = url; + for (const char *p = webview_url + strlen(WEBVIEW_DATA_URL_PREFIX); *q = *p; + p++, q++) { + if (*q == '%' && *(p + 1) && *(p + 2)) { + sscanf(p + 1, "%02x", q); + p = p + 2; + } + } + + if (webBrowser2->lpVtbl->get_Document(webBrowser2, &lpDispatch) == S_OK) { + if (lpDispatch->lpVtbl->QueryInterface(lpDispatch, + iid_unref(&IID_IHTMLDocument2), + (void **)&htmlDoc2) == S_OK) { + if ((sfArray = SafeArrayCreate(VT_VARIANT, 1, + (SAFEARRAYBOUND *)&ArrayBound))) { + if (!SafeArrayAccessData(sfArray, (void **)&pVar)) { + pVar->vt = VT_BSTR; +#ifndef UNICODE + { + wchar_t *buffer = webview_to_utf16(url); + if (buffer == NULL) { + goto release; + } + bstr = SysAllocString(buffer); + GlobalFree(buffer); + } +#else + bstr = SysAllocString(string); +#endif + if ((pVar->bstrVal = bstr)) { + htmlDoc2->lpVtbl->write(htmlDoc2, sfArray); + htmlDoc2->lpVtbl->close(htmlDoc2); + } + } + SafeArrayDestroy(sfArray); + } + release: + free(url); + htmlDoc2->lpVtbl->Release(htmlDoc2); + } + lpDispatch->lpVtbl->Release(lpDispatch); + } + webBrowser2->lpVtbl->Release(webBrowser2); + return (0); + } + return (-5); +} + +static LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam) { + struct webview *w = (struct webview *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + switch (uMsg) { + case WM_CREATE: + w = (struct webview *)((CREATESTRUCT *)lParam)->lpCreateParams; + w->priv.hwnd = hwnd; + return EmbedBrowserObject(w); + case WM_DESTROY: + UnEmbedBrowserObject(w); + PostQuitMessage(0); + return TRUE; + case WM_SIZE: { + IWebBrowser2 *webBrowser2; + IOleObject *browser = *w->priv.browser; + if (browser->lpVtbl->QueryInterface(browser, iid_unref(&IID_IWebBrowser2), + (void **)&webBrowser2) == S_OK) { + RECT rect; + GetClientRect(hwnd, &rect); + webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right); + webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom); + } + return TRUE; + } + case WM_WEBVIEW_DISPATCH: { + webview_dispatch_fn f = (webview_dispatch_fn)wParam; + void *arg = (void *)lParam; + (*f)(w, arg); + return TRUE; + } + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +#define WEBVIEW_KEY_FEATURE_BROWSER_EMULATION \ + "Software\\Microsoft\\Internet " \ + "Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION" + +static int webview_fix_ie_compat_mode() { + HKEY hKey; + DWORD ie_version = 11000; + TCHAR appname[MAX_PATH + 1]; + TCHAR *p; + if (GetModuleFileName(NULL, appname, MAX_PATH + 1) == 0) { + return -1; + } + for (p = &appname[strlen(appname) - 1]; p != appname && *p != '\\'; p--) { + } + p++; + if (RegCreateKey(HKEY_CURRENT_USER, WEBVIEW_KEY_FEATURE_BROWSER_EMULATION, + &hKey) != ERROR_SUCCESS) { + return -1; + } + if (RegSetValueEx(hKey, p, 0, REG_DWORD, (BYTE *)&ie_version, + sizeof(ie_version)) != ERROR_SUCCESS) { + RegCloseKey(hKey); + return -1; + } + RegCloseKey(hKey); + return 0; +} + +WEBVIEW_API int webview_init(struct webview *w) { + WNDCLASSEX wc; + HINSTANCE hInstance; + DWORD style; + RECT clientRect; + RECT rect; + + if (webview_fix_ie_compat_mode() < 0) { + return -1; + } + + hInstance = GetModuleHandle(NULL); + if (hInstance == NULL) { + return -1; + } + if (OleInitialize(NULL) != S_OK) { + return -1; + } + ZeroMemory(&wc, sizeof(WNDCLASSEX)); + wc.cbSize = sizeof(WNDCLASSEX); + wc.hInstance = hInstance; + wc.lpfnWndProc = wndproc; + wc.lpszClassName = classname; + RegisterClassEx(&wc); + + style = WS_OVERLAPPEDWINDOW; + if (!w->resizable) { + style = WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU; + } + + rect.left = 0; + rect.top = 0; + rect.right = w->width; + rect.bottom = w->height; + AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, 0); + + GetClientRect(GetDesktopWindow(), &clientRect); + int left = (clientRect.right / 2) - ((rect.right - rect.left) / 2); + int top = (clientRect.bottom / 2) - ((rect.bottom - rect.top) / 2); + rect.right = rect.right - rect.left + left; + rect.left = left; + rect.bottom = rect.bottom - rect.top + top; + rect.top = top; + + w->priv.hwnd = + CreateWindowEx(0, classname, w->title, style, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + HWND_DESKTOP, NULL, hInstance, (void *)w); + if (w->priv.hwnd == 0) { + OleUninitialize(); + return -1; + } + + SetWindowLongPtr(w->priv.hwnd, GWLP_USERDATA, (LONG_PTR)w); + + DisplayHTMLPage(w); + + SetWindowText(w->priv.hwnd, w->title); + ShowWindow(w->priv.hwnd, SW_SHOWDEFAULT); + UpdateWindow(w->priv.hwnd); + SetFocus(w->priv.hwnd); + + return 0; +} + +WEBVIEW_API int webview_loop(struct webview *w, int blocking) { + MSG msg; + if (blocking) { + GetMessage(&msg, 0, 0, 0); + } else { + PeekMessage(&msg, 0, 0, 0, PM_REMOVE); + } + switch (msg.message) { + case WM_QUIT: + return -1; + case WM_COMMAND: + case WM_KEYDOWN: + case WM_KEYUP: { + HRESULT r = S_OK; + IWebBrowser2 *webBrowser2; + IOleObject *browser = *w->priv.browser; + if (browser->lpVtbl->QueryInterface(browser, iid_unref(&IID_IWebBrowser2), + (void **)&webBrowser2) == S_OK) { + IOleInPlaceActiveObject *pIOIPAO; + if (browser->lpVtbl->QueryInterface( + browser, iid_unref(&IID_IOleInPlaceActiveObject), + (void **)&pIOIPAO) == S_OK) { + r = pIOIPAO->lpVtbl->TranslateAccelerator(pIOIPAO, &msg); + pIOIPAO->lpVtbl->Release(pIOIPAO); + } + webBrowser2->lpVtbl->Release(webBrowser2); + } + if (r != S_FALSE) { + break; + } + } + default: + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return 0; +} + +WEBVIEW_API int webview_eval(struct webview *w, const char *js) { + IWebBrowser2 *webBrowser2; + IHTMLDocument2 *htmlDoc2; + IDispatch *docDispatch; + IDispatch *scriptDispatch; + if ((*w->priv.browser) + ->lpVtbl->QueryInterface((*w->priv.browser), + iid_unref(&IID_IWebBrowser2), + (void **)&webBrowser2) != S_OK) { + return -1; + } + + if (webBrowser2->lpVtbl->get_Document(webBrowser2, &docDispatch) != S_OK) { + return -1; + } + if (docDispatch->lpVtbl->QueryInterface(docDispatch, + iid_unref(&IID_IHTMLDocument2), + (void **)&htmlDoc2) != S_OK) { + return -1; + } + if (htmlDoc2->lpVtbl->get_Script(htmlDoc2, &scriptDispatch) != S_OK) { + return -1; + } + DISPID dispid; + BSTR evalStr = SysAllocString(L"eval"); + if (scriptDispatch->lpVtbl->GetIDsOfNames( + scriptDispatch, iid_unref(&IID_NULL), &evalStr, 1, + LOCALE_SYSTEM_DEFAULT, &dispid) != S_OK) { + SysFreeString(evalStr); + return -1; + } + SysFreeString(evalStr); + + DISPPARAMS params; + VARIANT arg; + VARIANT result; + EXCEPINFO excepInfo; + UINT nArgErr = (UINT)-1; + params.cArgs = 1; + params.cNamedArgs = 0; + params.rgvarg = &arg; + arg.vt = VT_BSTR; + static const char *prologue = "(function(){"; + static const char *epilogue = ";})();"; + int n = strlen(prologue) + strlen(epilogue) + strlen(js) + 1; + char *eval = (char *)malloc(n); + snprintf(eval, n, "%s%s%s", prologue, js, epilogue); + wchar_t *buf = webview_to_utf16(eval); + if (buf == NULL) { + return -1; + } + arg.bstrVal = SysAllocString(buf); + if (scriptDispatch->lpVtbl->Invoke( + scriptDispatch, dispid, iid_unref(&IID_NULL), 0, DISPATCH_METHOD, + ¶ms, &result, &excepInfo, &nArgErr) != S_OK) { + return -1; + } + SysFreeString(arg.bstrVal); + free(eval); + scriptDispatch->lpVtbl->Release(scriptDispatch); + htmlDoc2->lpVtbl->Release(htmlDoc2); + docDispatch->lpVtbl->Release(docDispatch); + return 0; +} + +WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn, + void *arg) { + PostMessageW(w->priv.hwnd, WM_WEBVIEW_DISPATCH, (WPARAM)fn, (LPARAM)arg); +} + +WEBVIEW_API void webview_set_title(struct webview *w, const char *title) { + SetWindowText(w->priv.hwnd, title); +} + +WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) { + if (w->priv.is_fullscreen == !!fullscreen) { + return; + } + if (w->priv.is_fullscreen == 0) { + w->priv.saved_style = GetWindowLong(w->priv.hwnd, GWL_STYLE); + w->priv.saved_ex_style = GetWindowLong(w->priv.hwnd, GWL_EXSTYLE); + GetWindowRect(w->priv.hwnd, &w->priv.saved_rect); + } + w->priv.is_fullscreen = !!fullscreen; + if (fullscreen) { + MONITORINFO monitor_info; + SetWindowLong(w->priv.hwnd, GWL_STYLE, + w->priv.saved_style & ~(WS_CAPTION | WS_THICKFRAME)); + SetWindowLong(w->priv.hwnd, GWL_EXSTYLE, + w->priv.saved_ex_style & + ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | + WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); + monitor_info.cbSize = sizeof(monitor_info); + GetMonitorInfo(MonitorFromWindow(w->priv.hwnd, MONITOR_DEFAULTTONEAREST), + &monitor_info); + RECT r; + r.left = monitor_info.rcMonitor.left; + r.top = monitor_info.rcMonitor.top; + r.right = monitor_info.rcMonitor.right; + r.bottom = monitor_info.rcMonitor.bottom; + SetWindowPos(w->priv.hwnd, NULL, r.left, r.top, r.right - r.left, + r.bottom - r.top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + } else { + SetWindowLong(w->priv.hwnd, GWL_STYLE, w->priv.saved_style); + SetWindowLong(w->priv.hwnd, GWL_EXSTYLE, w->priv.saved_ex_style); + SetWindowPos(w->priv.hwnd, NULL, w->priv.saved_rect.left, + w->priv.saved_rect.top, + w->priv.saved_rect.right - w->priv.saved_rect.left, + w->priv.saved_rect.bottom - w->priv.saved_rect.top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + } +} + +WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g, + uint8_t b, uint8_t a) { + HBRUSH brush = CreateSolidBrush(RGB(r, g, b)); + SetClassLongPtr(w->priv.hwnd, GCLP_HBRBACKGROUND, (LONG_PTR)brush); +} + +/* These are missing parts from MinGW */ +#ifndef __IFileDialog_INTERFACE_DEFINED__ +#define __IFileDialog_INTERFACE_DEFINED__ +enum _FILEOPENDIALOGOPTIONS { + FOS_OVERWRITEPROMPT = 0x2, + FOS_STRICTFILETYPES = 0x4, + FOS_NOCHANGEDIR = 0x8, + FOS_PICKFOLDERS = 0x20, + FOS_FORCEFILESYSTEM = 0x40, + FOS_ALLNONSTORAGEITEMS = 0x80, + FOS_NOVALIDATE = 0x100, + FOS_ALLOWMULTISELECT = 0x200, + FOS_PATHMUSTEXIST = 0x800, + FOS_FILEMUSTEXIST = 0x1000, + FOS_CREATEPROMPT = 0x2000, + FOS_SHAREAWARE = 0x4000, + FOS_NOREADONLYRETURN = 0x8000, + FOS_NOTESTFILECREATE = 0x10000, + FOS_HIDEMRUPLACES = 0x20000, + FOS_HIDEPINNEDPLACES = 0x40000, + FOS_NODEREFERENCELINKS = 0x100000, + FOS_DONTADDTORECENT = 0x2000000, + FOS_FORCESHOWHIDDEN = 0x10000000, + FOS_DEFAULTNOMINIMODE = 0x20000000, + FOS_FORCEPREVIEWPANEON = 0x40000000 +}; +typedef DWORD FILEOPENDIALOGOPTIONS; +typedef enum FDAP { FDAP_BOTTOM = 0, FDAP_TOP = 1 } FDAP; +DEFINE_GUID(IID_IFileDialog, 0x42f85136, 0xdb7e, 0x439c, 0x85, 0xf1, 0xe4, 0x07, + 0x5d, 0x13, 0x5f, 0xc8); +typedef struct IFileDialogVtbl { + BEGIN_INTERFACE + HRESULT(STDMETHODCALLTYPE *QueryInterface) + (IFileDialog *This, REFIID riid, void **ppvObject); + ULONG(STDMETHODCALLTYPE *AddRef)(IFileDialog *This); + ULONG(STDMETHODCALLTYPE *Release)(IFileDialog *This); + HRESULT(STDMETHODCALLTYPE *Show)(IFileDialog *This, HWND hwndOwner); + HRESULT(STDMETHODCALLTYPE *SetFileTypes) + (IFileDialog *This, UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec); + HRESULT(STDMETHODCALLTYPE *SetFileTypeIndex) + (IFileDialog *This, UINT iFileType); + HRESULT(STDMETHODCALLTYPE *GetFileTypeIndex) + (IFileDialog *This, UINT *piFileType); + HRESULT(STDMETHODCALLTYPE *Advise) + (IFileDialog *This, IFileDialogEvents *pfde, DWORD *pdwCookie); + HRESULT(STDMETHODCALLTYPE *Unadvise)(IFileDialog *This, DWORD dwCookie); + HRESULT(STDMETHODCALLTYPE *SetOptions) + (IFileDialog *This, FILEOPENDIALOGOPTIONS fos); + HRESULT(STDMETHODCALLTYPE *GetOptions) + (IFileDialog *This, FILEOPENDIALOGOPTIONS *pfos); + HRESULT(STDMETHODCALLTYPE *SetDefaultFolder) + (IFileDialog *This, IShellItem *psi); + HRESULT(STDMETHODCALLTYPE *SetFolder)(IFileDialog *This, IShellItem *psi); + HRESULT(STDMETHODCALLTYPE *GetFolder)(IFileDialog *This, IShellItem **ppsi); + HRESULT(STDMETHODCALLTYPE *GetCurrentSelection) + (IFileDialog *This, IShellItem **ppsi); + HRESULT(STDMETHODCALLTYPE *SetFileName)(IFileDialog *This, LPCWSTR pszName); + HRESULT(STDMETHODCALLTYPE *GetFileName)(IFileDialog *This, LPWSTR *pszName); + HRESULT(STDMETHODCALLTYPE *SetTitle)(IFileDialog *This, LPCWSTR pszTitle); + HRESULT(STDMETHODCALLTYPE *SetOkButtonLabel) + (IFileDialog *This, LPCWSTR pszText); + HRESULT(STDMETHODCALLTYPE *SetFileNameLabel) + (IFileDialog *This, LPCWSTR pszLabel); + HRESULT(STDMETHODCALLTYPE *GetResult)(IFileDialog *This, IShellItem **ppsi); + HRESULT(STDMETHODCALLTYPE *AddPlace) + (IFileDialog *This, IShellItem *psi, FDAP fdap); + HRESULT(STDMETHODCALLTYPE *SetDefaultExtension) + (IFileDialog *This, LPCWSTR pszDefaultExtension); + HRESULT(STDMETHODCALLTYPE *Close)(IFileDialog *This, HRESULT hr); + HRESULT(STDMETHODCALLTYPE *SetClientGuid)(IFileDialog *This, REFGUID guid); + HRESULT(STDMETHODCALLTYPE *ClearClientData)(IFileDialog *This); + HRESULT(STDMETHODCALLTYPE *SetFilter) + (IFileDialog *This, IShellItemFilter *pFilter); + END_INTERFACE +} IFileDialogVtbl; +interface IFileDialog { + CONST_VTBL IFileDialogVtbl *lpVtbl; +}; +DEFINE_GUID(IID_IFileOpenDialog, 0xd57c7288, 0xd4ad, 0x4768, 0xbe, 0x02, 0x9d, + 0x96, 0x95, 0x32, 0xd9, 0x60); +DEFINE_GUID(IID_IFileSaveDialog, 0x84bccd23, 0x5fde, 0x4cdb, 0xae, 0xa4, 0xaf, + 0x64, 0xb8, 0x3d, 0x78, 0xab); +#endif + +WEBVIEW_API void webview_dialog(struct webview *w, + enum webview_dialog_type dlgtype, int flags, + const char *title, const char *arg, + char *result, size_t resultsz) { + if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN || + dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) { + IFileDialog *dlg = NULL; + IShellItem *res = NULL; + WCHAR *ws = NULL; + char *s = NULL; + FILEOPENDIALOGOPTIONS opts, add_opts; + if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) { + if (CoCreateInstance( + iid_unref(&CLSID_FileOpenDialog), NULL, CLSCTX_INPROC_SERVER, + iid_unref(&IID_IFileOpenDialog), (void **)&dlg) != S_OK) { + goto error_dlg; + } + if (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY) { + add_opts |= FOS_PICKFOLDERS; + } + add_opts |= FOS_NOCHANGEDIR | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | + FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_SHAREAWARE | + FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS | + FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE; + } else { + if (CoCreateInstance( + iid_unref(&CLSID_FileSaveDialog), NULL, CLSCTX_INPROC_SERVER, + iid_unref(&IID_IFileSaveDialog), (void **)&dlg) != S_OK) { + goto error_dlg; + } + add_opts |= FOS_OVERWRITEPROMPT | FOS_NOCHANGEDIR | + FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_SHAREAWARE | + FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS | + FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE; + } + if (dlg->lpVtbl->GetOptions(dlg, &opts) != S_OK) { + goto error_dlg; + } + opts &= ~FOS_NOREADONLYRETURN; + opts |= add_opts; + if (dlg->lpVtbl->SetOptions(dlg, opts) != S_OK) { + goto error_dlg; + } + if (dlg->lpVtbl->Show(dlg, w->priv.hwnd) != S_OK) { + goto error_dlg; + } + if (dlg->lpVtbl->GetResult(dlg, &res) != S_OK) { + goto error_dlg; + } + if (res->lpVtbl->GetDisplayName(res, SIGDN_FILESYSPATH, &ws) != S_OK) { + goto error_result; + } + s = webview_from_utf16(ws); + strncpy(result, s, resultsz); + result[resultsz - 1] = '\0'; + CoTaskMemFree(ws); + error_result: + res->lpVtbl->Release(res); + error_dlg: + dlg->lpVtbl->Release(dlg); + return; + } else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) { +#if 0 + /* MinGW often doesn't contain TaskDialog, we'll use MessageBox for now */ + WCHAR *wtitle = webview_to_utf16(title); + WCHAR *warg = webview_to_utf16(arg); + TaskDialog(w->priv.hwnd, NULL, NULL, wtitle, warg, 0, NULL, NULL); + GlobalFree(warg); + GlobalFree(wtitle); +#else + UINT type = MB_OK; + switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) { + case WEBVIEW_DIALOG_FLAG_INFO: + type |= MB_ICONINFORMATION; + break; + case WEBVIEW_DIALOG_FLAG_WARNING: + type |= MB_ICONWARNING; + break; + case WEBVIEW_DIALOG_FLAG_ERROR: + type |= MB_ICONERROR; + break; + } + MessageBox(w->priv.hwnd, arg, title, type); +#endif + } +} + +WEBVIEW_API void webview_terminate(struct webview *w) { PostQuitMessage(0); } +WEBVIEW_API void webview_exit(struct webview *w) { OleUninitialize(); } +WEBVIEW_API void webview_print_log(const char *s) { OutputDebugString(s); } + +#endif /* WEBVIEW_WINAPI */ + +#if defined(WEBVIEW_COCOA) +#if (!defined MAC_OS_X_VERSION_10_12) || \ + MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 +#define NSAlertStyleWarning NSWarningAlertStyle +#define NSAlertStyleCritical NSCriticalAlertStyle +#define NSWindowStyleMaskResizable NSResizableWindowMask +#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask +#define NSWindowStyleMaskTitled NSTitledWindowMask +#define NSWindowStyleMaskClosable NSClosableWindowMask +#define NSWindowStyleMaskFullScreen NSFullScreenWindowMask +#define NSEventMaskAny NSAnyEventMask +#define NSEventModifierFlagCommand NSCommandKeyMask +#define NSEventModifierFlagOption NSAlternateKeyMask +#define NSAlertStyleInformational NSInformationalAlertStyle +#endif /* MAC_OS_X_VERSION_10_12 */ +#if (!defined MAC_OS_X_VERSION_10_13) || \ + MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13 +#define NSModalResponseOK NSFileHandlingPanelOKButton +#endif /* MAC_OS_X_VERSION_10_12, MAC_OS_X_VERSION_10_13 */ +static void webview_window_will_close(id self, SEL cmd, id notification) { + struct webview *w = + (struct webview *)objc_getAssociatedObject(self, "webview"); + webview_terminate(w); +} + +static BOOL webview_is_selector_excluded_from_web_script(id self, SEL cmd, + SEL selector) { + return selector != @selector(invoke:); +} + +static NSString *webview_webscript_name_for_selector(id self, SEL cmd, + SEL selector) { + return selector == @selector(invoke:) ? @"invoke" : nil; +} + +static void webview_did_clear_window_object(id self, SEL cmd, id webview, + id script, id frame) { + [script setValue:self forKey:@"external"]; +} + +static void webview_external_invoke(id self, SEL cmd, id arg) { + struct webview *w = + (struct webview *)objc_getAssociatedObject(self, "webview"); + if (w == NULL || w->external_invoke_cb == NULL) { + return; + } + if ([arg isKindOfClass:[NSString class]] == NO) { + return; + } + w->external_invoke_cb(w, [(NSString *)(arg)UTF8String]); +} + +WEBVIEW_API int webview_init(struct webview *w) { + w->priv.pool = [[NSAutoreleasePool alloc] init]; + [NSApplication sharedApplication]; + + Class webViewDelegateClass = + objc_allocateClassPair([NSObject class], "WebViewDelegate", 0); + class_addMethod(webViewDelegateClass, sel_registerName("windowWillClose:"), + (IMP)webview_window_will_close, "v@:@"); + class_addMethod(object_getClass(webViewDelegateClass), + sel_registerName("isSelectorExcludedFromWebScript:"), + (IMP)webview_is_selector_excluded_from_web_script, "c@::"); + class_addMethod(object_getClass(webViewDelegateClass), + sel_registerName("webScriptNameForSelector:"), + (IMP)webview_webscript_name_for_selector, "c@::"); + class_addMethod(webViewDelegateClass, + sel_registerName("webView:didClearWindowObject:forFrame:"), + (IMP)webview_did_clear_window_object, "v@:@@@"); + class_addMethod(webViewDelegateClass, sel_registerName("invoke:"), + (IMP)webview_external_invoke, "v@:@"); + objc_registerClassPair(webViewDelegateClass); + + w->priv.windowDelegate = [[webViewDelegateClass alloc] init]; + objc_setAssociatedObject(w->priv.windowDelegate, "webview", (id)(w), + OBJC_ASSOCIATION_ASSIGN); + + NSRect r = NSMakeRect(0, 0, w->width, w->height); + NSUInteger style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable; + if (w->resizable) { + style = style | NSWindowStyleMaskResizable; + // style = style | NSTexturedBackgroundWindowMask; + // style = style | NSUnifiedTitleAndToolbarWindowMask; + } + + // Transparent title bar + // if (w->transparentTitlebar) { + // style = style | NSFullSizeContentViewWindowMask | NSUnifiedTitleAndToolbarWindowMask | NSTexturedBackgroundWindowMask; + // } + + + w->priv.window = [[NSWindow alloc] initWithContentRect:r + styleMask:style + backing:NSBackingStoreBuffered + defer:NO]; + [w->priv.window autorelease]; + + // Title + NSString *nsTitle = [NSString stringWithUTF8String:w->title]; + [w->priv.window setTitle:nsTitle]; + + [w->priv.window setDelegate:w->priv.windowDelegate]; + [w->priv.window center]; + + // NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"wat"]; + // toolbar.showsBaselineSeparator = NO; + // [w->priv.window setToolbar:toolbar]; + + // if (w->transparentTitlebar) { + + + // // Configure window look with hidden toolbar + // [w->priv.window setTitlebarAppearsTransparent:YES]; + // [w->priv.window setTitleVisibility:NSWindowTitleHidden]; + // // w->priv.window.isMovableByWindowBackground = true; + // } + + [[NSUserDefaults standardUserDefaults] setBool:!!w->debug + forKey:@"WebKitDeveloperExtras"]; + [[NSUserDefaults standardUserDefaults] synchronize]; + w->priv.webview = + [[WebView alloc] initWithFrame:r frameName:@"WebView" groupName:nil]; + NSURL *nsURL = [NSURL + URLWithString:[NSString stringWithUTF8String:webview_check_url(w->url)]]; + [[w->priv.webview mainFrame] loadRequest:[NSURLRequest requestWithURL:nsURL]]; + + [w->priv.webview setAutoresizesSubviews:YES]; + [w->priv.webview + setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + w->priv.webview.frameLoadDelegate = w->priv.windowDelegate; + [[w->priv.window contentView] addSubview:w->priv.webview]; + [w->priv.window orderFrontRegardless]; + + // Disable scrolling - make this configurable + [[[w->priv.webview mainFrame] frameView] setAllowsScrolling:NO]; + +// +// ----> Enables WebGL but won't pass the app store guidelines +// +// WebPreferences *p = [w->priv.webview preferences]; +// if ([p respondsToSelector:@selector(setWebGLEnabled:)]) { +// [p setWebGLEnabled:YES]; +// } + + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + [NSApp finishLaunching]; + [NSApp activateIgnoringOtherApps:YES]; + + NSMenu *menubar = [[[NSMenu alloc] initWithTitle:@""] autorelease]; + + NSString *appName = [[NSProcessInfo processInfo] processName]; + NSMenuItem *appMenuItem = + [[[NSMenuItem alloc] initWithTitle:appName action:NULL keyEquivalent:@""] + autorelease]; + NSMenu *appMenu = [[[NSMenu alloc] initWithTitle:appName] autorelease]; + [appMenuItem setSubmenu:appMenu]; + [menubar addItem:appMenuItem]; + + NSString *title = [@"Hide " stringByAppendingString:appName]; + NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:title + action:@selector(hide:) + keyEquivalent:@"h"] autorelease]; + [appMenu addItem:item]; + item = [[[NSMenuItem alloc] initWithTitle:@"Hide Others" + action:@selector(hideOtherApplications:) + keyEquivalent:@"h"] autorelease]; + [item setKeyEquivalentModifierMask:(NSEventModifierFlagOption | + NSEventModifierFlagCommand)]; + [appMenu addItem:item]; + item = [[[NSMenuItem alloc] initWithTitle:@"Show All" + action:@selector(unhideAllApplications:) + keyEquivalent:@""] autorelease]; + [appMenu addItem:item]; + [appMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Quit " stringByAppendingString:appName]; + item = [[[NSMenuItem alloc] initWithTitle:title + action:@selector(terminate:) + keyEquivalent:@"q"] autorelease]; + [appMenu addItem:item]; + + [NSApp setMainMenu:menubar]; + + w->priv.should_exit = 0; + return 0; +} + +WEBVIEW_API int webview_loop(struct webview *w, int blocking) { + NSDate *until = (blocking ? [NSDate distantFuture] : [NSDate distantPast]); + NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny + untilDate:until + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event) { + [NSApp sendEvent:event]; + } + return w->priv.should_exit; +} + +WEBVIEW_API int webview_eval(struct webview *w, const char *js) { + NSString *nsJS = [NSString stringWithUTF8String:js]; + [[w->priv.webview windowScriptObject] evaluateWebScript:nsJS]; + return 0; +} + +WEBVIEW_API void webview_set_title(struct webview *w, const char *title) { + NSString *nsTitle = [NSString stringWithUTF8String:title]; + [w->priv.window setTitle:nsTitle]; +} + +WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) { + int b = ((([w->priv.window styleMask] & NSWindowStyleMaskFullScreen) == + NSWindowStyleMaskFullScreen) + ? 1 + : 0); + if (b != fullscreen) { + [w->priv.window toggleFullScreen:nil]; + } +} + +WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g, + uint8_t b, uint8_t a) { + [w->priv.window setBackgroundColor:[NSColor colorWithRed:(CGFloat)r / 255.0 + green:(CGFloat)g / 255.0 + blue:(CGFloat)b / 255.0 + alpha:(CGFloat)a / 255.0]]; + if (0.5 >= ((r / 255.0 * 299.0) + (g / 255.0 * 587.0) + (b / 255.0 * 114.0)) / + 1000.0) { + [w->priv.window + setAppearance:[NSAppearance + appearanceNamed:NSAppearanceNameVibrantDark]]; + } else { + [w->priv.window + setAppearance:[NSAppearance + appearanceNamed:NSAppearanceNameVibrantLight]]; + } + [w->priv.window setOpaque:NO]; + [w->priv.window setTitlebarAppearsTransparent:YES]; + [w->priv.webview setDrawsBackground:NO]; +} + +WEBVIEW_API void webview_dialog(struct webview *w, + enum webview_dialog_type dlgtype, int flags, + const char *title, const char *arg, + char *result, size_t resultsz) { + if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN || + dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) { + NSSavePanel *panel; + if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) { + NSOpenPanel *openPanel = [NSOpenPanel openPanel]; + if (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY) { + [openPanel setCanChooseFiles:NO]; + [openPanel setCanChooseDirectories:YES]; + } else { + [openPanel setCanChooseFiles:YES]; + [openPanel setCanChooseDirectories:NO]; + } + [openPanel setResolvesAliases:NO]; + [openPanel setAllowsMultipleSelection:NO]; + panel = openPanel; + } else { + panel = [NSSavePanel savePanel]; + } + [panel setCanCreateDirectories:YES]; + [panel setShowsHiddenFiles:YES]; + [panel setExtensionHidden:NO]; + [panel setCanSelectHiddenExtension:NO]; + [panel setTreatsFilePackagesAsDirectories:YES]; + [panel beginSheetModalForWindow:w->priv.window + completionHandler:^(NSInteger result) { + [NSApp stopModalWithCode:result]; + }]; + if ([NSApp runModalForWindow:panel] == NSModalResponseOK) { + const char *filename = [[[panel URL] path] UTF8String]; + strlcpy(result, filename, resultsz); + } + } else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) { + NSAlert *a = [NSAlert new]; + switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) { + case WEBVIEW_DIALOG_FLAG_INFO: + [a setAlertStyle:NSAlertStyleInformational]; + break; + case WEBVIEW_DIALOG_FLAG_WARNING: + NSLog(@"warning"); + [a setAlertStyle:NSAlertStyleWarning]; + break; + case WEBVIEW_DIALOG_FLAG_ERROR: + NSLog(@"error"); + [a setAlertStyle:NSAlertStyleCritical]; + break; + } + [a setShowsHelp:NO]; + [a setShowsSuppressionButton:NO]; + [a setMessageText:[NSString stringWithUTF8String:title]]; + [a setInformativeText:[NSString stringWithUTF8String:arg]]; + [a addButtonWithTitle:@"OK"]; + [a runModal]; + [a release]; + } +} + +static void webview_dispatch_cb(void *arg) { + struct webview_dispatch_arg *context = (struct webview_dispatch_arg *)arg; + (context->fn)(context->w, context->arg); + free(context); +} + +WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn, + void *arg) { + struct webview_dispatch_arg *context = (struct webview_dispatch_arg *)malloc( + sizeof(struct webview_dispatch_arg)); + context->w = w; + context->arg = arg; + context->fn = fn; + dispatch_async_f(dispatch_get_main_queue(), context, webview_dispatch_cb); +} + +WEBVIEW_API void webview_terminate(struct webview *w) { + w->priv.should_exit = 1; +} +WEBVIEW_API void webview_exit(struct webview *w) { [NSApp terminate:NSApp]; } +WEBVIEW_API void webview_print_log(const char *s) { NSLog(@"%s", s); } + +#endif /* WEBVIEW_COCOA */ + +#endif /* WEBVIEW_IMPLEMENTATION */ + +#ifdef __cplusplus +} +#endif + +#endif /* WEBVIEW_H */